bzoj4817: [Sdoi2017]树点涂色

Posted Nico&11101001

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了bzoj4817: [Sdoi2017]树点涂色相关的知识,希望对你有一定的参考价值。

题目链接

bzoj4817: [Sdoi2017]树点涂色

题解

数据结构.....大概很容易看出是道lct 然后弃疗
操作1很想lct里面的access操作
那么对于操作2
设F[i]=i点到lct根路径上的splay数(也就是虚边数)+1
那么对于操作2的(x,y)
ans(x,y)=F[x]+F[y]-(F(lca(x,y)))+1;
对于操作3的(x),就是在x的子树中取max,我们可以用dfs序+线段树维护
考虑操作1对操作3的影响
在access的时候,当一个边由虚变实,此时该边所连的深度大的点的颜色种类-1
反之当一边由实变虚,此时该边所连的深度大的点的颜色种类+1
trick:保存当前节点在树中最左儿子的编号用以修改区间(即left[])
ps:中途电脑爆炸,然后重码QAQ,心态爆炸

代码

/*
 *
 * 数据结构+LCT+SEG_TREE
 *  
 */

#include<cstdio>
#include<algorithm>
const int maxn = 100007;
int n,m;
struct node{
    int v,next;
}edge[maxn<<1];
int head[maxn],num;
void Add_Edge(int u,int v) {
    edge[++num].v=v;edge[num].next=head[u];head[u]=num;
}
int idfn[maxn],ldfn[maxn],rdfn[maxn],f[maxn][20],dep[maxn];
int cnt=0,fa[maxn];
void dfs(int u,int F) {
    idfn[ldfn[u]=++cnt]=u,f[u][0]=fa[u]=F;
    for(int i=head[u];i;i=edge[i].next) {
        int v=edge[i].v;
        if(v!=F) dep[v]=dep[u]+1,dfs(v,u);
    }
    rdfn[u]=cnt;
    return ;
}
int LCA(int x,int y) {
    if(dep[x]<dep[y]) std::swap(x,y);
    for(int i=dep[x]-dep[y],j=0;i;i>>=1,++j)
        if(i&1)x=f[x][j];
    if(x==y) return x;
    for(int i=19;~i;--i) 
        if(f[x][i]!=f[y][i]) 
            x=f[x][i],y=f[y][i];
    return f[x][0];
}
class Segment_Tree {
#define lc x<<1
#define rc x<<1|1
    private :
        
        struct Node {
            int max,tag;
            Node () : tag(0){}
        };
        Node t[maxn<<2];
        
        void update(int x) {
            t[x].max=std::max(t[lc].max,t[rc].max);
        }
        void push_down(int x) {
            if(!t[x].tag)return;
            int k=t[x].tag;
            t[lc].max+=k;
            t[lc].tag+=k;
            t[rc].max+=k;
            t[rc].tag+=k;
            t[x].tag=0;
            return ;
        }
        
    public :

        void build (int x,int l,int r) {
            if(l==r) {
                t[x].max=dep[idfn[l]]+1;return;
            }
            int mid=l+r>>1;
            build(lc,l,mid);
            build(rc,mid+1,r);
            return update(x);
        }

        void modify(int x,int l,int r,int L,int  R,int w) {
            if(L<=l&&R>=r) {
                t[x].tag+=w;t[x].max+=w;
                return ;
            }
            push_down(x);
            int mid=l+r>>1;
            if(mid>=L) modify(lc,l,mid,L,R,w);
            if(mid<R) modify(rc,mid+1,r,L,R,w);
            return update(x);
        }
        
        int query(int x,int l,int r,int L,int  R) {
            if(L<=l&&R>=r) 
                return t[x].max;
            push_down(x);
            int mid=l+r>>1,ans=0;
            if(mid>=L) ans=std::max(ans,query(lc,l,mid,L,R));
            if(mid<R) ans=std::max(ans,query(rc,mid+1,r,L,R));
            return ans;
        }
#undef lc
#undef rc
}SEG_T;
class Link_Cut_tree {
#define lc ch[x][0]
#define rc ch[x][1]
    private : 
        
        int ch[maxn][2],left[maxn];
    void update(int x) {
        left[x]=lc ? left[lc]:x;
    }
    
    bool isroot(int x) {
        return ch[fa[x]][0]!=x&&ch[fa[x]][1]!=x;
    }
    
    void rotate(int x) {
        int y=fa[x],z=fa[y],d=(ch[y][1]==x)^1;
        if(!isroot(y)) ch[z][ch[z][1]==y]=x;fa[x]=z;
        ch[y][d^1]=ch[x][d],fa[ch[x][d]]=y;
        ch[x][d]=y;fa[y]=x;
        update(y),update(x);
    }
    
    void splay(int x) {
        while(!isroot(x)) {
            int y=fa[x],z=fa[y];
            if(!isroot(y)) {
                if(ch[y][1]==x^ch[z][1]==y) rotate(x);
                else rotate(y);
            }
            rotate(x);
        }
    }
    public:
        
        void init() {
            dfs(1,0),SEG_T.build(1,1,n);
            for(int i=1;i<=n;++i) left[i]=i;
            for(int j=1;j<20;j++)
                for(int i=1;i<=n;i++)
                    f[i][j]=f[f[i][j-1]][j-1];
        }
        
        void access(int x) {
            for(int t=0;x;x=fa[t=x]) {
                splay(x);
                if(rc) SEG_T.modify(1,1,n,ldfn[left[rc]],rdfn[left[rc]],1);
                rc=t;
                if(rc) SEG_T.modify(1,1,n,ldfn[left[rc]],rdfn[left[rc]],-1);
            }
            return ;
        }
        
        int query(int x) {
            int ans=0;
            for(;x;x=fa[x],ans++)splay(x);
            return ans;
        }
        
        int query(int u,int v) {
            return query(u)+query(v)-2*query(LCA(u,v))+1;
        }
#undef lc
#undef rc

}LCT;


int main() {
//  freopen("001.out","w",stdout);
    scanf("%d%d",&n,&m) ;
    for(int a,b,i=1;i<n;++i) {
        scanf("%d%d",&a,&b);
        Add_Edge(a,b);
        Add_Edge(b,a);
    }
    LCT.init();
    for(int opt,x,y,i=1;i<=m;++i) {
        scanf("%d",&opt);
        if(opt==1) scanf("%d",&x),LCT.access(x);
        if(opt==2) scanf("%d%d",&x,&y),printf("%d\n",LCT.query(x,y));
        else if(opt==3) scanf("%d",&x),printf("%d\n",SEG_T.query(1,1,n,ldfn[x],rdfn[x]));
    }
    return 0;
}

以上是关于bzoj4817: [Sdoi2017]树点涂色的主要内容,如果未能解决你的问题,请参考以下文章

[Bzoj4817] [Sdoi2017]树点涂色 (LCT神题)

bzoj4817: [Sdoi2017]树点涂色

BZOJ4817 [Sdoi2017]树点涂色

bzoj4817 [Sdoi2017]树点涂色

AC日记——[SDOI2017]树点涂色 bzoj 4817

[BZOJ4817][SDOI2017]树点涂色(LCT+DFS序线段树)