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

    既然是中文题目,这里便不给题意。

    分析:

      这个题的做法据说是启发式合并?

      但是我不会啊……

      进入正题,LCT是怎样做掉这道题的。记得在前面的一篇《大融合》的题解中,介绍过LCT维护子树信息的做法。

      一句话概括就是要维护虚子树和实子树的size,适时修改,保持其正确性。

      这道题关键并不在这,但我们必须要维护这样一个信息才可以做。

      很简单很直观的一个想法,因为我们每次合并两棵树时,新的重心必然出现在原来两个重心的路径上。

      这是为什么?我们假设如果不在这条路径上,而是其中一棵树的其他子树的某一点,那么我们发现这一点比起之前,size较大的一棵子树上又缀了一棵树(以这个点为根),所以一定不优。

      于是我们就合并树后把两棵原树的重心打通,(放到一个splay里),这时候尺寸就派上用场了,我们就在这个splay里查找,因为重心反正肯定存在于这个splay中了,那么我们就维护一个左尺寸,一个右尺寸。左边大了我们就让重心往左移动,右边大了就往右移动,直到两边的尺寸都小于等于总尺寸的一半,就好啦!(别忘了多个重心时的编号最小化)

    代码:

     1 #include<bits/stdc++.h>
     2 #define lc(x) t[x][0]
     3 #define rc(x) t[x][1]
     4 using namespace std;
     5 const int N=100005;
     6 const int inf=0x3f3f3f3f;
     7 struct LCT{
     8     int t[N][2],s[N],rev[N],fa[N],sx[N],sz[N],tp;
     9     void pushup(int x){
    10         sz[x]=sz[lc(x)]+sz[rc(x)]+sx[x]+1;
    11     } bool pdrt(int x){
    12         return rc(fa[x])!=x&&lc(fa[x])!=x;
    13     } void revers(int x){
    14         rev[x]^=1;swap(lc(x),rc(x));
    15     } void pushdown(int x){
    16         if(rev[x]){ rev[x]=0;
    17             if(lc(x)) revers(lc(x));
    18             if(rc(x)) revers(rc(x));
    19         } return ;
    20     } void rotate(int x){
    21         int y=fa[x];int z=fa[y];
    22         int dy=(rc(y)==x),dz=(rc(z)==y);
    23         if(!pdrt(y)) t[z][dz]=x;
    24         t[y][dy]=t[x][dy^1];fa[t[y][dy]]=y;
    25         t[x][dy^1]=y;fa[y]=x;fa[x]=z;
    26         pushup(y);return ;
    27     } void splay(int x){
    28         s[++tp]=x;
    29         for(int i=x;!pdrt(i);i=fa[i])
    30         s[++tp]=fa[i];
    31         while(tp) pushdown(s[tp--]);
    32         while(!pdrt(x)){
    33             int y=fa[x];int z=fa[y];
    34             if(!pdrt(y))
    35             if(rc(y)==x^rc(z)==y) rotate(x);
    36             else rotate(y);rotate(x);
    37         } pushup(x);return ;
    38     } void access(int x){
    39         for(int i=0;x;x=fa[i=x])
    40         splay(x),sx[x]+=sz[rc(x)],
    41         sx[x]-=sz[rc(x)=i],pushup(x);
    42     } void mkrt(int x){
    43         access(x);splay(x);revers(x);
    44     } void split(int x,int y){
    45         mkrt(x);access(y);splay(y);
    46     } void link(int x,int y){
    47         split(x,y);sx[fa[x]=y]+=sz[x];
    48         pushup(y);
    49     } int update(int x){
    50         int l,r,o=sz[x]&1,sm=sz[x]>>1,
    51         ls=0,rs=0,np=inf,nl,nr;
    52         while(x){
    53             pushdown(x);
    54             nl=sz[l=lc(x)]+ls;nr=sz[r=rc(x)]+rs;
    55             if(nl<=sm&&nr<=sm){
    56                 if(o){np=x;break;}
    57                 else if(np>x) np=x;
    58             } if(nl<nr) ls+=sz[l]+sx[x]+1,x=r;
    59             else rs+=sz[r]+sx[x]+1,x=l;
    60         } splay(np);return np;
    61     }
    62 }t;int n,m,fa[N];
    63 int get(int x){
    64     return fa[x]==x?x:fa[x]=get(fa[x]);
    65 } int main(){
    66     char c[5];int rox=0;//尤为重要,必须赋0; 
    67     scanf("%d%d",&n,&m);
    68     for(int i=1;i<=n;i++) 
    69     t.sz[i]=1,fa[i]=i,rox^=i;
    70     while(m--){
    71         scanf("%s",c);int x,y,z;
    72         if(c[0]=='A'){
    73             scanf("%d%d",&x,&y);t.link(x,y);
    74             t.split(x=get(x),y=get(y));
    75             z=t.update(y);rox=(rox^x^y^z);
    76             fa[x]=fa[y]=fa[z]=z;
    77         } else if(c[0]=='Q'){
    78             scanf("%d",&x);
    79             printf("%d
    ",get(x));
    80         } else printf("%d
    ",rox);
    81     } return 0;
    82 }
  • 相关阅读:
    Thinkphp5 对接百度云对象存储 BOS (上传、删除)
    php 删除富文本编辑器保存内容中的其他代码(保留中文)
    ffmreg thinkphp 控制器 获取音频视频详细信息(获取时长)
    selenium+testng+java+poi进行excel的数据参数化
    linux中磁盘配额管理
    linux中挂载和卸载文件系统
    linux中vi编辑器的练习
    Linux基础命令
    Nginx流量复制
    Python脚本
  • 原文地址:https://www.cnblogs.com/Alan-Luo/p/10188156.html
Copyright © 2011-2022 走看看