HDU 2475 BOX 动态树 Link-Cut Tree

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的左右关系。

 

看了很多代码,觉得还是写不好,总觉得别人的用起来不顺,最后是在自己原来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 }
View Code

 

posted @ 2015-04-25 12:59  辰帆  阅读(228)  评论(0编辑  收藏  举报