• BZOJ3510 首都


    题目描述

    在X星球上有N个国家,每个国家占据着X星球的一座城市。由于国家之间是敌对关系,所以不同国家的两个城市是不会有公路相连的。 
    X星球上战乱频发,如果A国打败了B国,那么B国将永远从这个星球消失,而B国的国土也将归A国管辖。A国国王为了加强统治,会在A国和B国之间修建一条公路,即选择原A国的某个城市和B国某个城市,修建一条连接这两座城市的公路。 
    同样为了便于统治自己的国家,国家的首都会选在某个使得其他城市到它距离之和最小的城市,这里的距离是指需要经过公路的条数,如果有多个这样的城市,编号最小的将成为首都。 
    现在告诉你发生在X星球的战事,需要你处理一些关于国家首都的信息,具体地,有如下3种信息需要处理: 
    1、A x y:表示某两个国家发生战乱,战胜国选择了x城市和y城市,在它们之间修建公路(保证其中城市一个在战胜国另一个在战败国)。 
    2、Q x:询问当前编号为x的城市所在国家的首都。 
    3、Xor:询问当前所有国家首都编号的异或和。 

    输入

    第一行是整数N,M,表示城市数和需要处理的信息数。 
    接下来每行是一个信息,格式如题目描述(A、Q、Xor中的某一种)。 

    输出

    输出包含若干行,为处理Q和Xor信息的结果。 

    样例输入

    10 10 
    Xor 
    Q 1 
    A 10 1 
    A 1 4 
    Q 4 
    Q 10 
    A 7 6 
    Xor 
    Q 7 
    Xor 

    样例输出

    11 





    2

    题解

    LCT维护子树信息

    看了好几个小时的题解还是半懂不懂orz

    先考虑连接两棵树

    有两个性质

    1.重心必在点数多的子树内

    2.点数多的子树上重心移动的距离不超过点数少的子树的点数

    然后就是连上之后,把这条路径拉出来,dfs一遍,枚举选哪一个点,然后判一下最优就好了

      1 // luogu-judger-enable-o2
      2 //minamoto
      3 #include<iostream>
      4 #include<cstdio>
      5 #include<algorithm>
      6 using std::swap;
      7 #define getc() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++)
      8 char buf[1<<21],*p1=buf,*p2=buf;
      9 inline int read(){
     10     #define num ch-'0'
     11     char ch;bool flag=0;int res;
     12     while(!isdigit(ch=getc()))
     13     (ch=='-')&&(flag=true);
     14     for(res=num;isdigit(ch=getc());res=res*10+num);
     15     (flag)&&(res=-res);
     16     #undef num
     17     return res;
     18 }
     19 char obuf[1<<24],*o=obuf;
     20 inline void print(int x){
     21     if(x>9) print(x/10);
     22     *o++=x%10+48;
     23 }
     24 const int N=100005;
     25 int fa[N],st[N],sum[N],si[N],rev[N],ch[N][2],top,s;
     26 inline bool isroot(int x){return ch[fa[x]][0]!=x&&ch[fa[x]][1]!=x;}
     27 inline void pushup(int x){sum[x]=sum[ch[x][0]]+sum[ch[x][1]]+si[x]+1;}
     28 inline void pushdown(int x){
     29     if(rev[x]){
     30         swap(ch[x][0],ch[x][1]);
     31         rev[ch[x][0]]^=1,rev[ch[x][1]]^=1;
     32         rev[x]=0;
     33     }
     34 }
     35 void rotate(int x){
     36     int y=fa[x],z=fa[y],d=ch[y][1]==x;
     37     if(!isroot(y)) ch[z][ch[z][1]==y]=x;
     38     fa[x]=z,fa[y]=x,fa[ch[x][d^1]]=y,ch[y][d]=ch[x][d^1],ch[x][d^1]=y,pushup(y);
     39 }
     40 void down(int x){
     41     if(!isroot(x)) down(fa[x]);
     42     pushdown(x);
     43 }
     44 void splay(int x){
     45     down(x);
     46     for(int y=fa[x],z=fa[y];!isroot(x);y=fa[x],z=fa[y]){
     47         if(!isroot(y))
     48         ((ch[y][1]==x)^(ch[z][1]==y))?rotate(x):rotate(y);
     49         rotate(x);
     50     }
     51     pushup(x);
     52 }
     53 void access(int x){
     54     for(int y=0;x;x=fa[y=x])
     55     splay(x),si[x]+=sum[ch[x][1]],si[x]-=sum[ch[x][1]=y],pushup(x);
     56 }
     57 void makeroot(int x){
     58     access(x),splay(x),rev[x]^=1;
     59 }
     60 int findroot(int x){
     61     access(x),splay(x),pushdown(x);
     62     while(ch[x][0]) pushdown(x=ch[x][0]);
     63     return x;
     64 }
     65 void split(int x,int y){
     66     makeroot(x),access(y),splay(y);
     67 }
     68 void link(int x,int y){
     69     split(x,y),fa[x]=y,si[y]+=sum[x],pushup(y);
     70 }
     71 void dfs(int x){
     72     pushdown(x);
     73     if(ch[x][0]) dfs(ch[x][0]);
     74     if(top>s) return;
     75     st[++top]=x;
     76     if(top>s) return;
     77     if(ch[x][1]) dfs(ch[x][1]);
     78 }
     79 int main(){
     80     //freopen("testdata.in","r",stdin);
     81     int n=read(),m=read(),res=0;
     82     for(int i=1;i<=n;++i) sum[i]=1,res^=i;
     83     while(m--){
     84         char c;
     85         while((c=getc())!='Q'&&c!='A'&&c!='X');
     86         switch(c){
     87             case 'A':{
     88                 int x=read(),y=read();
     89                 int tx=findroot(x),ty=findroot(y),ts;
     90                 res^=tx^ty;
     91                 splay(tx),splay(ty);
     92                 if(sum[tx]>sum[ty]||(sum[tx]==sum[ty]&&x<y)) swap(x,y),swap(tx,ty);
     93                 s=sum[tx],ts=sum[tx]+sum[ty],link(x,y),access(x),splay(ty);
     94                 top=0,dfs(ty);int r=ty;
     95                 for(int i=1;i<=top;++i){
     96                     splay(st[i]);int t=si[st[i]]+1+sum[ch[st[i]][1]];
     97                     if(ts-t<t||(ts-t==t&&st[i]<=r)) r=st[i];
     98                     else break;
     99                     /*枚举原重心到连接点之间的路径
    100                     t表示枚举到某一点时另一棵子树的大小
    101                     如果这棵子树大于另一边或那啥,更新答案
    102                     否则之前的答案最优,直接退出*/
    103                 }
    104                 makeroot(r),res^=r;
    105                 break;
    106             }
    107             case 'Q':{
    108                 int x=read();
    109                 print(findroot(x)),*o++='
    ';
    110                 break;
    111             }
    112             case 'X':{
    113                 print(res),*o++='
    ';
    114                 break;
    115             }
    116         }
    117     }
    118     fwrite(obuf,o-obuf,1,stdout);
    119     return 0;
    120 }
  • 相关阅读:
    CodeForces 697B Barnicle 模拟
    15.三数之和
    167.两数之和
    209.长度最小子数组-sliding window
    COMP9313 Week9a-0
    树总纲(To be continued)
    COMP9517 Week8
    COMP9313 week8b Pipeline
    94. 二叉树的中序遍历
    COMP9313 Week8 Classification and PySpark MLlib
  • 原文地址:https://www.cnblogs.com/bztMinamoto/p/9418679.html
Copyright © 2020-2023  润新知