【bzoj4817】[Sdoi2017]树点涂色 【树链剖分】【LCT】【线段树】

blog终于update了= =
题目链接
题意:给一棵树,支持三种操作
1 x:
把点x到根节点的路径上所有的点染上一种没有用过的新颜色。
2 x y:
求x到y的路径的权值。
3 x
在以x为根的子树中选择一个点,使得这个点到根节点的路径权值最大,求最大权值。
题解
通过观察,我们发现同一种颜色一定连在一起的,因此第2个询问就相当于求链上颜色段的数目,直接使用树剖套线段树维护一下。
第一个修改操作其实和LCT的access很像,把到根路径上的所有点都丢到一起。所以我们可以对于1操作直接access,这样每个节点的到根路径的的权值就是虚边的数量+1。我们就在access的时候,虚边变化时维护一下就好。注意每一棵LCT中的小splay实际的根是最靠左的节点,就是中序遍历最靠前的节点。
其实不需要分两种方法的= = 第二种询问直接在LCT上维护就行了。
代码

#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
const int N=100005;
int n,m,op,u,v;
namespace tree{
    int cnt,tot,head[N],to[N*2],nxt[N*2];
    int idx,fa[N],dep[N],siz[N],son[N],top[N],dfn[N],pos[N];
    struct data{
        int lc,rc,sc;
        bool flag;
        data(){
            flag=false;
        }
    }col[N*4];
    int tag[N*4];
    data merge(data a,data b){
        if(!a.flag){
            return b;
        }else if(!b.flag){
            return a;
        }
        data c;
        c.flag=true;
        c.sc=a.sc+b.sc;
        if(a.rc==b.lc){
            c.sc--;
        }
        c.lc=a.lc;
        c.rc=b.rc;
        return c;
    }
    void adde(int u,int v){
        to[++cnt]=v;
        nxt[cnt]=head[u];
        head[u]=cnt;
    }
    void dfs(int u){
        int v;
        siz[u]=1;
        for(int i=head[u];i;i=nxt[i]){
            v=to[i];
            if(v!=fa[u]){
                fa[v]=u;
                dep[v]=dep[u]+1;
                dfs(v);
                siz[u]+=siz[v];
                if(!son[u]||siz[son[u]]<siz[v]){
                    son[u]=v;
                }
            }
        }
    }
    void dfs(int u,int tp){
        top[u]=tp;
        dfn[u]=++idx;
        pos[idx]=u;
        if(son[u]){
            dfs(son[u],tp);
        }
        int v;
        for(int i=head[u];i;i=nxt[i]){
            v=to[i];
            if(v!=fa[u]&&v!=son[u]){
                dfs(v,v);
            }
        }
    }
    void build(int o,int l,int r){
        if(l==r){
            col[o].sc=1;
            col[o].lc=col[o].rc=pos[l];
            col[o].flag=true;
            return;
        }
        int mid=(l+r)/2;
        build(o*2,l,mid);
        build(o*2+1,mid+1,r);
        col[o]=merge(col[o*2],col[o*2+1]);
    }
    void pushdown(int o){
        if(tag[o]){
            tag[o*2]=tag[o*2+1]=col[o*2].lc=col[o*2].rc=col[o*2+1].lc=col[o*2+1].rc=tag[o];
            col[o*2].sc=col[o*2+1].sc=1;
            tag[o]=0;
        }
    }
    void update(int o,int l,int r,int L,int R){
        if(L==l&&R==r){
            tag[o]=col[o].lc=col[o].rc=tot;
            col[o].sc=1;
            col[o].flag=true;
            return;
        }
        pushdown(o);
        int mid=(l+r)/2;
        if(R<=mid){
            update(o*2,l,mid,L,R);
        }else if(L>mid){
            update(o*2+1,mid+1,r,L,R);
        }else{
            update(o*2,l,mid,L,mid);
            update(o*2+1,mid+1,r,mid+1,R);
        }
        col[o]=merge(col[o*2],col[o*2+1]);
    }
    data query(int o,int l,int r,int L,int R){
        if(L==l&&R==r){
            return col[o];
        }
        pushdown(o);
        int mid=(l+r)/2;
        if(R<=mid){
            return query(o*2,l,mid,L,R);
        }else if(L>mid){
            return query(o*2+1,mid+1,r,L,R);
        }else{
            return merge(query(o*2,l,mid,L,mid),query(o*2+1,mid+1,r,mid+1,R));
        }
    }
    void modify(int u){
        tot++;
        while(top[u]!=1){
            update(1,1,n,dfn[top[u]],dfn[u]);
            u=fa[top[u]];
        }
        update(1,1,n,1,dfn[u]);
    }
    int solve(int x,int y){
        data ansx,ansy,res;
        bool flagx=false,flagy=false;
        while(top[x]!=top[y]){
            if(dep[top[x]]>dep[top[y]]){
                res=query(1,1,n,dfn[top[x]],dfn[x]);
                if(!flagx){
                    flagx=true;
                    ansx=res;
                }else{
                    ansx=merge(ansx,res);
                }
                x=fa[top[x]];
            }else{
                res=query(1,1,n,dfn[top[y]],dfn[y]);
                if(!flagy){
                    flagy=true;
                    ansy=res;
                }else{
                    ansy=merge(res,ansy);
                }
                y=fa[top[y]];
            }
        }
        if(dep[x]<dep[y]){
            res=query(1,1,n,dfn[x],dfn[y]);
            if(!flagy){
                flagy=true;
                ansy=res;
            }else{
                ansy=merge(res,ansy);
            }
        }else{
            res=query(1,1,n,dfn[y],dfn[x]);
            if(!flagx){
                flagx=true;
                ansx=res;
            }else{
                ansx=merge(ansx,res);
            }
        }
        if(!flagy){
            return ansx.sc;
        }else if(!flagx){
            return ansy.sc;
        }else{
            return merge(ansx,ansy).sc;
        }
    }
}
namespace sgt{
    int maxn[N*4],tag[N*4];
    void pushdown(int o){
        if(tag[o]){
            tag[o*2]+=tag[o];
            tag[o*2+1]+=tag[o];
            maxn[o*2]+=tag[o];
            maxn[o*2+1]+=tag[o];
            tag[o]=0;
        }
    }
    void update(int o,int l,int r,int L,int R,int v){
        if(L==l&&R==r){
            maxn[o]+=v;
            tag[o]+=v;
            return;
        }
        pushdown(o);
        int mid=(l+r)/2;
        if(R<=mid){
            update(o*2,l,mid,L,R,v);
        }else if(L>mid){
            update(o*2+1,mid+1,r,L,R,v);
        }else{
            update(o*2,l,mid,L,mid,v);
            update(o*2+1,mid+1,r,mid+1,R,v);
        }
        maxn[o]=max(maxn[o*2],maxn[o*2+1]);
    }
    int query(int o,int l,int r,int L,int R){
        if(L==l&&R==r){
            return maxn[o];
        }
        pushdown(o);
        int mid=(l+r)/2;
        if(R<=mid){
            return query(o*2,l,mid,L,R);
        }else if(L>mid){
            return query(o*2+1,mid+1,r,L,R);
        }else{
            return max(query(o*2,l,mid,L,mid),query(o*2+1,mid+1,r,mid+1,R));
        }
    }
}
namespace lct{
    int fa[N],ch[N][2];
    void build(int u){
        fa[u]=tree::fa[u];
        int v;
        for(int i=tree::head[u];i;i=tree::nxt[i]){
            v=tree::to[i];
            if(v!=tree::fa[u]){
                build(v);
            }
        }
    }
    bool isroot(int u){
        return u!=ch[fa[u]][0]&&u!=ch[fa[u]][1];
    }
    int which(int u){
        return u==ch[fa[u]][1];
    }
    void rotate(int x){
        int y=fa[x],md=which(x);
        if(!isroot(y)){
            ch[fa[y]][which(y)]=x;
        }
        fa[x]=fa[y];
        ch[y][md]=ch[x][!md];
        fa[ch[y][md]]=y;
        ch[x][!md]=y;
        fa[y]=x;
    }
    void splay(int u){
        while(!isroot(u)){
            if(!isroot(fa[u])){
                rotate(which(u)==which(fa[u])?fa[u]:u);
            }
            rotate(u);
        }
    }
    int getroot(int u){
        while(ch[u][0]){
            u=ch[u][0];
        }
        return u;
    }
    void access(int u){
        for(int v=0,res;u;v=u,u=fa[u]){
            splay(u);
            if(ch[u][1]){
                res=getroot(ch[u][1]);
                sgt::update(1,1,n,tree::dfn[res],tree::dfn[res]+tree::siz[res]-1,1);
            }
            ch[u][1]=v;
            if(ch[u][1]){
                res=getroot(ch[u][1]);
                sgt::update(1,1,n,tree::dfn[res],tree::dfn[res]+tree::siz[res]-1,-1);
            }
        }
    }
}
int main(){
    scanf("%d%d",&n,&m);
    for(int i=1;i<n;i++){
        scanf("%d%d",&u,&v);
        tree::adde(u,v);
        tree::adde(v,u);
    }
    tree::dfs(1);
    tree::dfs(1,1);
    tree::build(1,1,n);
    for(int i=1;i<=n;i++){
        sgt::update(1,1,n,i,i,tree::dep[tree::pos[i]]+1);
    }
    tree::tot=n;
    lct::build(1);
    while(m--){
        scanf("%d%d",&op,&u);
        if(op==1){
            tree::modify(u);
            lct::access(u);
        }else if(op==2){
            scanf("%d",&v);
            printf("%d\n",tree::solve(u,v));
        }else{
            printf("%d\n",sgt::query(1,1,n,tree::dfn[u],tree::dfn[u]+tree::siz[u]-1));
        }
    }
    return 0;
}
posted @ 2018-08-02 22:09  ez_2016gdgzoi471  阅读(117)  评论(0编辑  收藏  举报