码迷,mamicode.com
首页 > 其他好文 > 详细

P4299 首都

时间:2019-01-28 18:24:03      阅读:135      评论:0      收藏:0      [点我收藏+]

标签:while   update   操作   [1]   维护   roo   play   get   splay   

题目

P4299 首都

做法

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

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

而找重心过程中跟整个链有关

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\n",Xor);
        else if(s[0]=='Q'){
            LL x(Read());
            printf("%d\n",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;
}

P4299 首都

标签:while   update   操作   [1]   维护   roo   play   get   splay   

原文地址:https://www.cnblogs.com/y2823774827y/p/10331230.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!