zoukankan      html  css  js  c++  java
  • 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]='';
    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
    ",lct.findrt(x));
    116         }else printf("%d
    ",xsum);
    117     }
    118     return 0;
    119 }
  • 相关阅读:
    一种高压侧母线过流检测电路的实现
    编程逻辑之状态机学习
    STM32——驱动DS18B20
    迪文屏所有控件测试
    EC11使用原理简介以及LL库源码
    FreeRTOS API使用栗子
    常用官网链接
    CubeMX之FreeRTOS学习day02
    跟工程师学嵌入式开发:基于STM32和μC OS-Ⅲ(学习笔记)
    CubeMX之FreeRTOS学习day01
  • 原文地址:https://www.cnblogs.com/guapisolo/p/9697102.html
Copyright © 2011-2022 走看看