【XSY2534】【BZOJ4817】树点涂色 LCT 倍增 线段树 dfs序

来源:互联网 发布:ae for mac破解版下载 编辑:程序博客网 时间:2024/05/16 17:16

题目大意

​  Bob有一棵n个点的有根树,其中1号点是根节点。Bob在每个点上涂了颜色,并且每个点上的颜色不同。定义一条路径的权值是:这条路径上的点(包括起点和终点)共有多少种不同的颜色。Bob可能会进行这几种操作:

​  1 x:把点x到根节点的路径上所有的点染上一种没有用过的新颜色。

​  2 x y:求xy的路径的权值。

​  3 x y:在以x为根的子树中选择一个点,使得这个点到根节点的路径权值最大,求最大权值。

​  Bob一共会进行m次操作

  n,m100000

题解

​  注意到操作1就是access操作,可以用LCT维护。

​  设fi=i到根的路径权值,则操作2的答案为fx+fy2flca+1

​  如果只有操作1和操作2的话,就可以暴力往上跳,但是操作3就没那么好处理了。

​  所以我们可以用线段树+dfs序维护fi

​  access切换虚实边时一棵子树的f全部+1,另一棵子树的f全部1

​  然后用倍增求LCA

  时间复杂度:O(nlog2n)

代码

#include<cstdio>#include<cstring>#include<algorithm>#include<cstdlib>#include<ctime>#include<utility>using namespace std;typedef long long ll;typedef pair<int,int> pii;int n,m;namespace seg{    int s[4000010];    int t[4000010];    int n;    void init()    {        n=0;        memset(s,0,sizeof s);        memset(t,0,sizeof t);    }    void at(int x,int v)    {        s[x]+=v;        t[x]+=v;    }    void push(int x)    {        at(x*2,t[x]);        at(x*2+1,t[x]);        t[x]=0;    }    void add(int p,int l,int r,int v,int L,int R)    {        if(l<=L&&r>=R)        {            at(p,v);            return;        }        if(t[p])            push(p);        int mid=(L+R)>>1;        if(l<=mid)            add(p*2,l,r,v,L,mid);        if(r>mid)            add(p*2+1,l,r,v,mid+1,R);        s[p]=max(s[p*2],s[p*2+1]);    }    int query(int p,int l,int r,int L,int R)    {        if(l<=L&&r>=R)            return s[p];        if(t[p])            push(p);        int mid=(L+R)>>1;        int res=0;        if(l<=mid)            res=max(res,query(p*2,l,r,L,mid));        if(r>mid)            res=max(res,query(p*2+1,l,r,mid+1,R));        return res;    }}namespace tree{    struct list    {        int v[200010];        int t[200010];        int h[100010];        int n;        list()        {            n=0;            memset(h,0,sizeof h);        }        void add(int x,int y)        {            n++;            v[n]=y;            t[n]=h[x];            h[x]=n;        }    };    list l;    int bg[100010];    int ed[100010];    int ti;    int f[100010][20];    int d[100010];    void init()    {        memset(f,0,sizeof f);        ti=0;    }    void dfs(int x,int fa,int dep)    {        bg[x]=++ti;        f[x][0]=fa;        d[x]=dep;        int i;        for(i=1;i<=19;i++)            f[x][i]=f[f[x][i-1]][i-1];        for(i=l.h[x];i;i=l.t[i])            if(l.v[i]!=fa)                dfs(l.v[i],x,dep+1);        ed[x]=ti;    }    int getlca(int x,int y)    {        if(d[x]<d[y])            swap(x,y);        int i;        for(i=19;i>=0;i--)            if(d[f[x][i]]>=d[y])                x=f[x][i];        if(x==y)            return x;        for(i=19;i>=0;i--)            if(f[x][i]!=f[y][i])            {                x=f[x][i];                y=f[y][i];            }        return f[x][0];    }}namespace lct{    int f[100010];    int a[100010][2];    void init()    {        memset(f,0,sizeof f);        memset(a,0,sizeof a);    }    int root(int x)    {        return a[f[x]][0]!=x&&a[f[x]][1]!=x;    }    void rotate(int x)    {        if(root(x))            return;        int p=f[x];        int q=f[p];        int ps=(x==a[p][1]);        int qs=(p==a[q][1]);        int ch=a[x][ps^1];        if(!root(p))            a[q][qs]=x;        a[x][ps^1]=p;        a[p][ps]=ch;        if(ch)            f[ch]=p;        f[p]=x;        f[x]=q;    }    int splay(int x)    {        while(!root(x))        {            int p=f[x];            if(!root(p))                if((x==a[p][1])^(p==a[f[p]][1]))                    rotate(p);                else                    rotate(x);            rotate(x);        }    }    void access(int x)    {        int t=0;        int y=x,z;        while(x)        {            splay(x);            if(t)            {                while(a[t][0])                    t=a[t][0];                splay(t);                seg::add(1,tree::bg[t],tree::ed[t],-1,1,n);            }            z=a[x][1];            a[x][1]=t;            if(z)            {                while(a[z][0])                    z=a[z][0];                splay(z);                seg::add(1,tree::bg[z],tree::ed[z],1,1,n);            }            t=x;            x=f[x];        }        splay(y);    }}int main(){    lct::init();    seg::init();    tree::init();//  freopen("bzoj4817.in","r",stdin);//  freopen("bzoj4817.out","w",stdout);    scanf("%d%d",&n,&m);    int i,op,x,y,ans;    for(i=1;i<n;i++)    {        scanf("%d%d",&x,&y);        tree::l.add(x,y);        tree::l.add(y,x);    }    tree::dfs(1,0,1);    for(i=2;i<=n;i++)        lct::f[i]=tree::f[i][0];    for(i=1;i<=n;i++)        seg::add(1,tree::bg[i],tree::bg[i],tree::d[i],1,n);    for(i=1;i<=m;i++)    {        scanf("%d",&op);        if(op==1)        {            scanf("%d",&x);            lct::access(x);        }        else if(op==2)        {            scanf("%d%d",&x,&y);            int lca=tree::getlca(x,y);            ans=seg::query(1,tree::bg[x],tree::bg[x],1,n)+                    seg::query(1,tree::bg[y],tree::bg[y],1,n)-                    2*seg::query(1,tree::bg[lca],tree::bg[lca],1,n)+1;            printf("%d\n",ans);        }        else        {            scanf("%d",&x);            ans=seg::query(1,tree::bg[x],tree::ed[x],1,n);            printf("%d\n",ans);        }    }    return 0;}