zoukankan      html  css  js  c++  java
  • P4299 首都 LCT

    题意:

    戳这里

    分析:

    题意:给定一片森林,三种操作:加边,求每个连通块的重心编号,求所有连通块重心编号异或和

    • 暴力

    好吧,这也不是很暴力的做法,(lca) 的启发式合并求重心,每次把小的连通块向大的连通块上一个点一个点合并,每次重心向大小超过 (frac{siz}{2}) 的方向挪动一格,复杂度 (O(nlog^2))

    • 优化:

    我们发现重心具有很优秀的性质,比如 合并两个连通块时,重心一定在原来两个连通块重心所连的路径上

    所以我们直接用 (lct) 维护,(split) 出两个重心之间的路径,然后路径就是一个 (splay) 层高 (log) 每次选择左右两个儿子中大于 (frac{siz}{2}) 的递归,复杂度 (O(nlog))

    代码:

    #include<bits/stdc++.h>
    
    using namespace std;
    
    namespace zzc
    {
        int read()
        {
            int x=0,f=1;char ch=getchar();
            while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
            while(isdigit(ch)){x=x*10+ch-48;ch=getchar();}
            return x*f;
        }
    
        const int maxn = 1e5+5;
        int n,m,ans;
        int anc[maxn];
        char opt[5];
        
        namespace lct
        {
            int top,q[maxn],fa[maxn],siz[maxn],isiz[maxn],ch[maxn][2],rev[maxn];
            void pushup(int rt){siz[rt]=siz[ch[rt][0]]+siz[ch[rt][1]]+isiz[rt]+1;}
            void pushdown(int rt){int l=ch[rt][0],r=ch[rt][1];if(rev[rt]){swap(ch[rt][0],ch[rt][1]);rev[l]^=1;rev[r]^=1;rev[rt]=0;}}
            bool isroot(int rt){return ch[fa[rt]][0]!=rt&&ch[fa[rt]][1]!=rt;}
            void rotate(int x)
            {
                int y=fa[x],z=fa[y],l,r;
                if(ch[y][0]==x)l=0;else l=1;r=l^1;
                if(!isroot(y)){if(ch[z][0]==y)ch[z][0]=x;else ch[z][1]=x;}
                fa[y]=x;fa[x]=z;fa[ch[x][r]]=y;
                ch[y][l]=ch[x][r];ch[x][r]=y;
                pushup(x);pushup(y);
            }
            void splay(int x)
            {
                top=1;q[top]=x;
                for(int i=x;!isroot(i);i=fa[i]) q[++top]=fa[i];
                for(int i=top;i;i--) pushdown(q[i]);
                while(!isroot(x))
                {
                    int y=fa[x],z=fa[y];
                    if(!isroot(y))
                    {
                        if((ch[z][0]==y)^(ch[y][0]==x)) rotate(x);
                        else rotate(y);
                    }
                    rotate(x);
                }
                pushup(x);
        	}
            void access(int x){for(int t=0;x;t=x,x=fa[x])splay(x),isiz[x]-=siz[t],isiz[x]+=siz[ch[x][1]],ch[x][1]=t,pushup(x);}
            void makeroot(int x){access(x);splay(x);rev[x]^=1;}
            void split(int x,int y){makeroot(x),access(y),splay(y);}
            void link(int x,int y){split(x,y),fa[x]=y,isiz[y]+=siz[x];pushup(y);}
            int search(int x)
            {
                int suml=0,sumr=0,rs,ls,sum=siz[x]>>1,chk=siz[x]&1,res=2e9+7,ll,rr;
                while(x)
                {
                    pushdown(x);
                    ll=suml+siz[ls=ch[x][0]];
                    rr=sumr+siz[rs=ch[x][1]];
                    if(ll<=sum&&rr<=sum)
                    {
                        if(chk){res=x;break;}
                        else if(x<res)res=x;
                    }
                    if(ll<rr) suml+=siz[ls]+isiz[x]+1,x=rs;
                    else sumr+=siz[rs]+isiz[x]+1,x=ls;
                }	
    			return res;
    		}
    	}
        using namespace lct;
        int find(int x){return anc[x]==x?x:anc[x]=find(anc[x]);}
    
        void work()
        {
            int x,y,z;
            n=read();m=read();
            for(int i=1;i<=n;i++) siz[i]=1,anc[i]=i,ans^=i;
            while(m--)
            {
                scanf("%s",opt);
                if(opt[0]=='A')
                {
                    x=read();y=read();
                    link(x,y);
    				x=find(x),y=find(y);
                    split(x,y);
                    z=search(y);
                    ans=ans^x^y^z;
                    anc[x]=anc[y]=anc[z]=z;
                }
                else if(opt[0]=='Q') x=read(),printf("%d
    ",find(x));
                else printf("%d
    ",ans);
            }
        }
    
    }
    
    int main()
    {
        zzc::work();
        return 0;
    }
    
  • 相关阅读:
    「CF1027」
    「CF1000G Two-Paths」
    「CF1009」
    「CF1008」
    Vi的按键(常用)
    【codeforces】Codeforces Round #643 (Div. 2)
    【codeforces】Codeforces Round #641 (Div. 2)
    【codeforces】 Codeforces Round #640 (Div. 4)
    【codeforces】Codeforces Round #642 (Div. 3)
    【codeforces】CF1345C Hilbert's Hotel
  • 原文地址:https://www.cnblogs.com/youth518/p/14236267.html
Copyright © 2011-2022 走看看