Box
Time Limit: 10000/5000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)
【Problem Description】
There are N boxes on the ground, which are labeled by numbers from 1 to N. The boxes are magical, the size of each one can be enlarged or reduced arbitrarily. Jack can perform the “MOVE x y” operation to the boxes: take out box x; if y = 0, put it on the ground; Otherwise, put it inside box y. All the boxes inside box x remain the same. It is possible that an operation is illegal, that is, if box y is contained (directly or indirectly) by box x, or if y is equal to x. In the following picture, box 2 and 4 are directly inside box 6, box 3 is directly inside box 4, box 5 is directly inside box 1, box 1 and 6 are on the ground.
The picture below shows the state after Jack performs “MOVE 4 1”:
Then he performs “MOVE 3 0”, the state becomes:
During a sequence of MOVE operations, Jack wants to know the root box of a specified box. The root box of box x is defined as the most outside box which contains box x. In the last picture, the root box of box 5 is box 1, and box 3’s root box is itself.
【Input】
Input contains several test cases. For each test case, the first line has an integer N (1 <= N <= 50000), representing the number of boxes. Next line has N integers: a1, a2, a3, ... , aN (0 <= ai <= N), describing the initial state of the boxes. If ai is 0, box i is on the ground, it is not contained by any box; Otherwise, box i is directly inside box ai. It is guaranteed that the input state is always correct (No loop exists). Next line has an integer M (1 <= M <= 100000), representing the number of MOVE operations and queries. On the next M lines, each line contains a MOVE operation or a query:
1. MOVE x y, 1 <= x <= N, 0 <= y <= N, which is described above. If an operation is illegal, just ignore it.
2. QUERY x, 1 <= x <= N, output the root box of box x.
【Output】
For each query, output the result on a single line. Use a blank line to separate each test case.
【Sample Input】
2 0 1 5 QUERY 1 QUERY 2 MOVE 2 0 MOVE 1 2 QUERY 1 6 0 6 4 6 1 0 4 MOVE 4 1 QUERY 3 MOVE 1 4 QUERY 1
【Sample Output】
1 1 2 1 1
【题意】
动态地维护一些盒子套盒子的操作,询问根。
【分析】
盒子与盒子的关系可以直观地用树的结构来表示,一个结点下的子结点可以表示大盒子里面直接套着的小盒子。
所以本题就是一个裸的Link-Cut Tree模型了。
关于LCT树,虽然坑了这么久,但是真的要我写的话,不知道该从哪开写。还是推荐Yang Zhe的QTREE论文吧。
看了很多代码,觉得还是写不好,总觉得别人的用起来不顺,最后是在自己原来Splay的基础上改的。
原本的整棵树是个splay,但是在LCT中,整棵树是由很多棵分散的Splay组合起来的,于是在其中的一些点上加上root标记,表示以这一点为根下面可以形成一棵splay树。多个这样的splay组合完成之后就是一棵LCT了。
后面的代码中加入了输入输出挂。。。。。。
1 /* *********************************************** 2 MYID : Chen Fan 3 LANG : G++ 4 PROG : HDU 2475 5 ************************************************ */ 6 7 #include <iostream> 8 #include <cstdio> 9 #include <cstring> 10 #include <algorithm> 11 12 using namespace std; 13 14 #define MAXN 50010 15 16 int sons[MAXN][2]; 17 int father[MAXN],pathfather[MAXN],data[MAXN]; 18 bool root[MAXN]; 19 int spttail=0; 20 21 void rotate(int x,int w) //rotate(node,0/1) 22 { 23 int y=father[x]; 24 25 sons[y][!w]=sons[x][w]; 26 if (sons[x][w]) father[sons[x][w]]=y; 27 father[x]=father[y]; 28 if (father[y]&&(!root[y])) sons[father[y]][y==sons[father[y]][1]]=x; 29 sons[x][w]=y; 30 father[y]=x; 31 32 if (root[y]) 33 { 34 root[x]=true; 35 root[y]=false; 36 } 37 } 38 39 void splay(int x) //splay(node) 40 { 41 while(!root[x]) 42 { 43 if (root[father[x]]) rotate(x,x==sons[father[x]][0]); 44 else 45 { 46 int t=father[x]; 47 int w=(sons[father[t]][0]==t); 48 if (sons[t][w]==x) 49 { 50 rotate(x,!w); 51 rotate(x,w); 52 } else 53 { 54 rotate(t,w); 55 rotate(x,w); 56 } 57 } 58 } 59 } 60 61 void access(int v) 62 { 63 int u=v; 64 v=0; 65 while(u) 66 { 67 splay(u); 68 root[sons[u][1]]=true; 69 sons[u][1]=v; 70 root[v]=false; 71 v=u; 72 u=father[u]; 73 } 74 } 75 76 int findroot(int v) 77 { 78 access(v); 79 splay(v); 80 while (sons[v][0]) v=sons[v][0]; 81 //splay(v,0); 82 return v; 83 } 84 85 void cut(int v) 86 { 87 access(v); 88 splay(v); 89 father[sons[v][0]]=0; 90 root[sons[v][0]]=true; 91 sons[v][0]=0; 92 } 93 94 void join(int v,int w) 95 { 96 if (!w) cut(v); 97 else 98 { 99 access(w); 100 splay(w); 101 int temp=v; 102 while(!root[temp]) temp=father[temp]; 103 if (temp!=w) 104 { 105 cut(v); 106 father[v]=w; 107 } 108 } 109 } 110 111 int INT() 112 { 113 char ch; 114 int res; 115 while (ch=getchar(),!isdigit(ch)); 116 for (res = ch - ‘0‘;ch = getchar(),isdigit(ch);) 117 res = res * 10 + ch - ‘0‘; 118 return res; 119 } 120 121 char CHAR() 122 { 123 char ch, res; 124 while (res = getchar(), !isalpha(res)); 125 while (ch = getchar(), isalpha(ch)); 126 return res; 127 } 128 129 int main() 130 { 131 //freopen("2475.txt","r",stdin); 132 133 int n; 134 double flag=false; 135 while(scanf("%d",&n)!=EOF) 136 { 137 if (flag) printf("\n"); 138 flag=true; 139 140 memset(father,0,sizeof(father)); 141 memset(sons,0,sizeof(sons)); 142 for (int i=1;i<=n;i++) 143 { 144 //scanf("%d",&father[i]); 145 father[i]=INT(); 146 root[i]=true; 147 } 148 149 int m; 150 m=INT(); 151 for (int i=1;i<=m;i++) 152 { 153 char s=CHAR(); 154 if (s==‘M‘) 155 { 156 int x,y; 157 x=INT(); 158 y=INT(); 159 join(x,y); 160 } else 161 { 162 int q; 163 q=INT(); 164 printf("%d\n",findroot(q)); 165 } 166 } 167 } 168 169 return 0; 170 }