zoukankan      html  css  js  c++  java
  • 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("
    ");
    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
    ",findroot(q));
    165             }
    166         }
    167     }
    168 
    169     return 0;
    170 }
    View Code
  • 相关阅读:
    [考试反思]0229省选模拟34:辉光
    [考试反思]0228省选模拟33:展望
    [考试反思]0226省选模拟32:磨灭
    [考试反思]0225省选模拟31:探索
    [考试反思]0224省选模拟30:仓皇
    [考试反思]0223省选模拟29:驻足
    [考试反思]0222省选模拟28:莫返
    大概是个寒假集训总结
    [考试反思]0220省选模拟27:怪异
    [考试反思]0219省选模拟26:精准
  • 原文地址:https://www.cnblogs.com/jcf94/p/4455770.html
Copyright © 2011-2022 走看看