• 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
    ",LCT.query(x,y));
            else if(opt==3) scanf("%d",&x),printf("%d
    ",SEG_T.query(1,1,n,ldfn[x],rdfn[x]));
        }
        return 0;
    }
    
    
  • 相关阅读:
    java nb
    hdu5293(2015多校1)--Tree chain problem(树状dp)
    点击交互的四种处理
    Java实现二维码技术探讨。
    折腾开源WRT的AC无线路由之路-1
    C语言及程序设计[套餐]课程主页
    09_Android中ContentProvider和Sqllite混合操作,一个项目调用另外一个项目的ContentProvider
    C语言打印字母金字塔(第一行是A 第二行是ABA ……)
    成员函数的const究竟修饰的是谁
    linux pdb调试总结
  • 原文地址:https://www.cnblogs.com/sssy/p/8641568.html
Copyright © 2020-2023  润新知