BZOJ 3510 首都 (LCT)

洛谷P4299传送门

题目大意:给你一颗树,边是一条一条连上去的

在连接过程中会存在询问,询问当前节点所在联通块(其实是一颗树)的重心是哪个节点

以及森林中所有树的重心的异或和

在做这道题之前,要先了解树的重心的一个性质:

两棵树合并时,新树的重心在合并后,原来两颗树的重心的两个节点构成的那条链上

了解了这条性质,思路就不难想了

当连接两个节点时,先寻找它们所在原树的重心,然后连接这两个节点,在取出两个原树重心那两个节点构成的那条链

每次寻找重心,连接节点,取出重心形成了链,复杂度约为O(logn)

如果我们暴力跑这条链,最差的情况是每次合并时,两颗树都是等长的链,然后像线段树那样从下往上合并,合并次数最多是O(nlogn)次,注意符合条件的重心最多只有2个,且子树的大小符合单调性,当越过所有重心时,及时跳出循环防止卡常

总复杂度O(nlog^2n)

然而我还是喜闻乐见得被卡常了

  1 #include <cstdio>
  2 #include <cstring>
  3 #include <algorithm>
  4 #define il inline
  5 #define N 200100
  6 using namespace std;
  7 
  8 int n,m,tp,num,xsum;
  9 int stk[N],que[N];
 10 
 11 struct LinkCutTree{
 12     #define ls ch[x][0]
 13     #define rs ch[x][1]
 14     int fa[N],ch[N][2],sz[N],sum[N],rv[N];
 15     il int idf(int x){return ch[fa[x]][0]==x?0:1;}
 16     il void rev(int x){swap(ls,rs),rv[x]^=1;}
 17     il int isroot(int x){return (ch[fa[x]][0]!=x&&ch[fa[x]][1]!=x)?1:0;}
 18     il void pushup(int x){sum[x]=sum[ls]+sum[rs]+sz[x]+1;}
 19     il void pushdown(int x)
 20     {
 21         if(rv[x]){
 22             if(ls) rev(ls);
 23             if(rs) rev(rs);
 24             rv[x]^=1;
 25         }
 26     }
 27     il void rot(int x)
 28     {
 29         int y=fa[x],ff=fa[y],px=idf(x),py=idf(y);
 30         if(!isroot(y)) ch[ff][py]=x;fa[x]=ff;
 31         ch[y][px]=ch[x][px^1],fa[ch[x][px^1]]=y;
 32         ch[x][px^1]=y,fa[y]=x;
 33         pushup(y),pushup(x);
 34     }
 35     void splay(int x)
 36     {
 37         int y=x;stk[++tp]=x;
 38         while(!isroot(y)){stk[++tp]=fa[y],y=fa[y];}
 39         while(tp){pushdown(stk[tp--]);}
 40         while(!isroot(x))
 41         {
 42             y=fa[x];
 43             if(isroot(y)) rot(x);
 44             else if(idf(y)==idf(x)) rot(y),rot(x);
 45             else rot(x),rot(x);
 46         }
 47     }
 48     void access(int x){
 49         for(int y=0;x;y=x,x=fa[x])
 50             splay(x),sz[x]-=sum[y],sz[x]+=sum[ch[x][1]],ch[x][1]=y,pushup(x);}
 51     il void mkroot(int x){access(x),splay(x),rev(x);}
 52     il void split(int x,int y){mkroot(y),access(x),splay(x);}
 53     il int findrt(int x){
 54         access(x),splay(x);
 55         while(1){
 56             pushdown(x);
 57             if(!ch[x][0])break;
 58             x=ch[x][0];}
 59         splay(x);return x;
 60     }
 61     void mid_dfs(int x)
 62     {
 63         pushdown(x);
 64         if(ls) mid_dfs(ls);
 65         que[++num]=x;
 66         if(rs) mid_dfs(rs);
 67     }
 68     il void link(int x,int y)
 69     {
 70         int gx=findrt(x),gy=findrt(y);
 71         xsum=xsum^gx^gy;
 72         if(sum[gx]<sum[gy]) swap(x,y),swap(gx,gy);
 73         split(x,y),fa[y]=x,sz[x]+=sum[y],pushup(x);
 74         num=0,split(gy,gx),mid_dfs(gy);
 75         int ma=sum[gy]/2,ans=0x3f3f3f3f;
 76         for(int i=1;i<=num;i++){
 77             splay(que[i]);
 78             if(sum[ch[que[i]][0]]<=ma&&sum[ch[que[i]][1]]<=ma&&que[i]<ans)
 79                 ans=que[i];
 80             if(sum[ch[que[i]][0]]>ma) break;}
 81         mkroot(ans);
 82         xsum^=ans;
 83     }
 84     #undef ls
 85     #undef rs
 86 }lct;
 87 int gint()
 88 {
 89     int rett=0,fh=1;char c=getchar();
 90     while(c<'0'||c>'9'){if(c=='-')fh=-1;c=getchar();}
 91     while(c>='0'&&c<='9'){rett=(rett<<3)+(rett<<1)+c-'0';c=getchar();}
 92     return rett*fh;
 93 }
 94 void gchar(char str[])
 95 {
 96     int p=0;char c=getchar();
 97     while(!((c>='A'&&c<='Z')||(c>='a'&&c<='z'))){c=getchar();}
 98     while((c>='A'&&c<='Z')||(c>='a'&&c<='z')){str[p++]=c;c=getchar();}
 99     str[p]='\0';
100 }
101 
102 int main()
103 {
104     scanf("%d%d",&n,&m);
105     for(int i=1;i<=n;i++) xsum^=i;
106     char q[10];int x,y;
107     for(int i=1;i<=m;i++)
108     {
109         gchar(q);
110         if(q[0]=='A'){
111             x=gint(),y=gint();
112             lct.link(x,y);
113         }else if(q[0]=='Q'){
114             x=gint();
115             printf("%d\n",lct.findrt(x));
116         }else printf("%d\n",xsum);
117     }
118     return 0;
119 }

 

posted @ 2018-09-24 22:39  guapisolo  阅读(168)  评论(0编辑  收藏  举报