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

    题目

    P4299 首都

    做法

    这题是动态维护树的重心,连边后找到两棵树的重心拉一条链(性质:新重心在链上),然后暴力爬

    要注意:

    1.是找重心的过程中要先把旋转标记放下来,因为(Splay(x)),这个操作只把(x)到根节点的跟上旋有关标记放下来
    而找重心过程中跟整个链有关

    2.并查集的时候记得把(z)也改变一下,不然会死循环,卡了好久(emmm)

    My complete code

    #include<cstdio>
    #include<iostream>
    #include<cstring>
    #include<string>
    #include<algorithm>
    using namespace std;
    typedef int LL;
    const LL maxn=200000,inf=0x3f3f3f3f;
    inline LL Read(){
    	LL x(0),f(1);char c=getchar();
    	while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
    	while(c>='0'&&c<='9')x=(x<<3)+(x<<1)+c-'0',c=getchar();
    	return x*f;
    }
    LL n,m,Xor;
    LL son[maxn][2],fa[maxn],sta[maxn],f[maxn],isum[maxn],sum[maxn],r[maxn];
    inline void Update(LL x){
    	sum[x]=sum[son[x][0]]+sum[son[x][1]]+isum[x]+1;
    }
    inline bool Notroot(LL x){
    	return son[fa[x]][0]==x||son[fa[x]][1]==x;
    }
    inline void Pushr(LL x){
    	swap(son[x][0],son[x][1]),r[x]^=1;
    }
    inline void Pushdown(LL x){
    	if(r[x]){
    		if(son[x][0]) Pushr(son[x][0]);
    		if(son[x][1]) Pushr(son[x][1]);
    		r[x]=0;
    	}
    }
    inline void Rotate(LL x){
    	LL y(fa[x]),z(fa[y]),lz(son[y][1]==x);
    	if(Notroot(y)) son[z][son[z][1]==y]=x;fa[x]=z;
    	son[y][lz]=son[x][lz^1];
    	if(son[y][lz]) fa[son[y][lz]]=y;
    	son[x][lz^1]=y; fa[y]=x;
    	Update(y),Update(x);
    }
    inline void Splay(LL x){
    	LL y(x),top(0);sta[++top]=y;
    	while(Notroot(y)) sta[++top]=y=fa[y];
    	while(top) Pushdown(sta[top--]);
    	while(Notroot(x)){
    		y=fa[x];
    		if(Notroot(y)){
    			LL z(fa[y]);
    			if(((son[y][1]==x)^(son[z][1]==y))==0) Rotate(y);
    			else Rotate(x);
    		}Rotate(x);
    	}
    }
    inline void Access(LL x){
    	for(LL y=0;x;y=x,x=fa[x]){
    	    Splay(x),isum[x]+=sum[son[x][1]];
    		son[x][1]=y;isum[x]-=sum[son[x][1]];
    		Update(x);
    	}
    }
    inline void Makeroot(LL x){
    	Access(x),Splay(x),Pushr(x);
    }
    inline void Split(LL x,LL y){
    	Makeroot(x),Access(y),Splay(y);
    }
    inline void Link(LL x,LL y){
        Makeroot(x),Access(y),Splay(y);
        fa[x]=y;
        isum[y]+=sum[x];
        Update(y);
    }
    
    LL Get_fa(LL x){
    	return f[x]=(f[x]==x?x:Get_fa(f[x]));
    }
    inline LL Get_w(LL x){
    	LL ji=sum[x]&1,M=sum[x]>>1,lsum(0),rsum(0),new_w(inf),nowl,nowr;
    	while(x){
    		Pushdown(x);
    		nowl=sum[son[x][0]]+lsum,nowr=sum[son[x][1]]+rsum;
    		if(nowl<=M&&nowr<=M){
    			if(ji){
    				new_w=x;
    				break;
    			}else
    			    new_w=min(new_w,x);
    		}
    		if(nowl<nowr){
    			lsum+=sum[son[x][0]]+isum[x]+1;
    			x=son[x][1];
    		}else{
    			rsum+=sum[son[x][1]]+isum[x]+1;
    			x=son[x][0];
    		}
    	}
    	Splay(new_w);
    	return new_w;
    }
    int main(){
    	n=Read(),m=Read();
    	for(LL i=1;i<=n;++i)
    	    sum[i]=1,f[i]=i,Xor^=i;
    	while(m--){
    		char s[100];
    		scanf(" %s",s);
    		if(s[0]=='X') printf("%d
    ",Xor);
    		else if(s[0]=='Q'){
    			LL x(Read());
    			printf("%d
    ",Get_fa(x));
    		}else{
    			LL x(Read()),y(Read());
    			Link(x,y);
    			Split(x=Get_fa(x),y=Get_fa(y));
    			LL z=Get_w(y);
    			f[x]=f[y]=f[z]=z;
    			Xor^=x^y^z;
    		}
    	}return 0;
    }
    
  • 相关阅读:
    最大生成树与最小生成树
    有限制的最短路spfa+优先队列
    KM算法(最优匹配)
    网络最大流解方程组
    网络费用流-最小k路径覆盖
    树链剖分-点的分治(点数为k且距离最长的点对)
    树链剖分-点的分治(链的点的个数为k的点对数)
    树链剖分-点的分治(dis[i]+dis[j]==k的点对数量)
    树链剖分-点的分治(dis[i]+dis[j]<=k的点对数量)
    无向图欧拉通路
  • 原文地址:https://www.cnblogs.com/y2823774827y/p/10331230.html
Copyright © 2011-2022 走看看