[SDOI2008] 洞穴勘测 (LCT模板)

bzoj 2049 传送门

洛谷P2147 传送门

这个大佬的LCT详解超级棒的!

Link-Cut Tree的基本思路是用splay的森林维护一条条树链。

splay的森林,顾名思义,就是若干splay组成的东西。

每个splay都有一个根节点,所以lct里的splay不能记录根节点,因为根节点有好多。

我们开一个bool数组记录每个点是否为根节点。

每个splay都维护一条重链,重链之间的轻链在splay里只从儿子指向父亲,而父亲并没有这个儿子。

就像图里的红箭头。

每个splay都表示一条重链,这个splay的中序遍历与链上节点的深度顺序是一致的。

接下来是splay里最重要的操作:access(p)

就是指打通从p到整棵树的树根的一条重链。

同时也把p下面接的链变成轻链。

之后还有一个操作:move_to_root,把p变成整棵树的根。

在access之后,p和树根之间是重链直接连接,而一个splay维护一个重链,所以此时p和根已经在一个splay里了。

我们只需要splay(p)即可。

但是这样的话破坏了深度的性质。

把左右反转一下就行了:reverse(p)

接下来就是link和cut的操作。

link(x,y)很简单,mtr(x),之后接一条从x到y的轻链即可。

cut(x,y)的话,mtr(x),access(y),splay(y),x就是y的左儿子了。删掉父子关系即可。

查询连通性:mtr(x),access(y),splay(y),x就在y的子树里了。x=f[x]一直往上跳,判断最后y的终点是不是x。

这些大概是最最基础的操作了,子树信息什么的都不用维护。

 

  1 #include<cstdio>
  2 #include<cstring>
  3 #include<algorithm>
  4 #define id(x) (s[f[x]][1]==x)
  5 using namespace std;
  6 
  7 int n,m;
  8 int f[10005],s[10005][2];
  9 bool rev[10005],rt[10005];
 10 
 11 void reverse(int p)
 12 {
 13     swap(s[p][0],s[p][1]);
 14     rev[p]^=1;
 15 }
 16 
 17 void pushdown(int p)
 18 {
 19     if(!rev[p])return;
 20     reverse(s[p][0]);
 21     reverse(s[p][1]);
 22     rev[p]=0;
 23 }
 24 
 25 void down(int p)
 26 {
 27     if(!rt[p])down(f[p]);
 28     pushdown(p);
 29 }
 30 
 31 void rotate(int p)
 32 {
 33     int k=id(p);
 34     int fa=f[p];
 35     if(rt[fa])rt[p]=1,rt[fa]=0;
 36     else s[f[fa]][id(fa)]=p;
 37     s[fa][k]=s[p][!k];
 38     s[p][!k]=fa;
 39     f[p]=f[fa];
 40     f[fa]=p;
 41     f[s[fa][k]]=fa;
 42 }
 43 
 44 void splay(int p)
 45 {
 46     down(p);
 47     while(!rt[p])
 48     {
 49         int fa=f[p];
 50         if(rt[fa])
 51         {
 52             rotate(p);
 53             return;
 54         }
 55         if(id(p)^id(fa))rotate(p);
 56         else rotate(fa);
 57         rotate(p);
 58     }
 59 }
 60 
 61 void access(int p)
 62 {
 63     int son=0;
 64     while(p)
 65     {
 66         splay(p);
 67         rt[s[p][1]]=1,rt[son]=0;
 68         s[p][1]=son;
 69         son=p,p=f[p];
 70     }
 71 }
 72 
 73 void mtr(int p)
 74 {
 75     access(p);
 76     splay(p);
 77     reverse(p);
 78 }
 79 
 80 void link(int x,int y)
 81 {
 82     mtr(x);
 83     f[x]=y;
 84 }
 85 
 86 void cut(int x,int y)
 87 {
 88     mtr(x);
 89     access(y);
 90     splay(y);
 91     s[y][0]=f[x]=0;
 92     rt[x]=1;
 93 }
 94 
 95 void check(int x,int y)
 96 {
 97     mtr(x);
 98     access(y);
 99     splay(y);
100     while(!rt[x])x=f[x];
101     printf("%s\n",(x==y?"Yes":"No"));
102 }
103 
104 int main()
105 {
106     scanf("%d%d",&n,&m);
107     for(int i=1;i<=n;i++)rt[i]=1;
108     char op[15];
109     int x,y;
110     while(m--)
111     {
112         scanf("%s",op+1);
113         scanf("%d%d",&x,&y);
114         if(op[1]=='C')link(x,y);
115         if(op[1]=='D')cut(x,y);
116         if(op[1]=='Q')check(x,y);
117     }
118     return 0;
119 }

 

posted @ 2018-09-14 21:07  cervusky  阅读(194)  评论(0编辑  收藏  举报

Contact with me