zoukankan      html  css  js  c++  java
  • 【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
    ",tree::solve(u,v));
            }else{
                printf("%d
    ",sgt::query(1,1,n,tree::dfn[u],tree::dfn[u]+tree::siz[u]-1));
            }
        }
        return 0;
    }
  • 相关阅读:
    windows 服务中托管asp.net core
    asp.net core自定义端口
    asp.net core 2.1 部署IIS(win10/win7)
    Centos7 安装Tomcat并运行程序
    centos7 安装java运行环境
    linux(centos7) 常用命令和快捷键 持续验证更新中...
    CentOS7 设置yum源
    dotnet core 入门命令
    二项式系数学习笔记
    [容斥原理][莫比乌斯反演] Codeforces 803F Coprime Subsequences
  • 原文地址:https://www.cnblogs.com/2016gdgzoi471/p/9476850.html
Copyright © 2011-2022 走看看