BZOJ 2002: [Hnoi2010]Bounce 弹飞绵羊 lct 动态树 splay

http://www.lydsy.com/JudgeOnline/problem.php?id=2002

http://blog.csdn.net/frods/article/details/52244250

本来以为lct是很难的算法没想到这么简单。。。也可能只是这道题简单。

看上去挺暴力的算法却有着很优秀的复杂度,很美丽了orz。

做法就是每次查询把子节点连一条到根的通路,所有的儿子都在父亲右儿子上,再splay查询的点。此时查询的点的左儿子的size就是所求的距离。

这个算法太神奇了orz。明明感觉有些粗笨简单但是透出朴实而容易ac的美,就像约翰内斯·维米尔的画,QAQ太令人愉悦了,QAQ谁会不喜欢splay呢。

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<algorithm>
 4 #include<cstring>
 5 #include<cmath>
 6 using namespace std;
 7 const int maxn=200010;
 8 int n,m;
 9 int kid[maxn][2]={},fa[maxn]={},siz[maxn]={};
10 inline bool CheckRoot(int x){return kid[fa[x]][0]!=x&&kid[fa[x]][1]!=x;}
11 inline void updata(int x){
12     siz[x]=1+siz[kid[x][0]]+siz[kid[x][1]];
13 }
14 void rotate(int x){
15     int y=fa[x];int fy=fa[y];
16     int l,r;
17     l=kid[y][0]==x?0:1; r=l^1;
18     if(!CheckRoot(y)){
19         if(kid[fy][0]==y)kid[fy][0]=x;
20         else kid[fy][1]=x;
21     }fa[x]=fy;
22     fa[y]=x;
23     fa[kid[x][r]]=y;
24     kid[y][l]=kid[x][r];kid[x][r]=y;
25     updata(y);//updata(x);这里不需要updata(x)因为splay只updata一下就可以惹
26 }
27 void Splay(int x){
28     while(!CheckRoot(x)){
29         int y=fa[x];int fy=fa[y];
30         if(!CheckRoot(y)){
31             if((x==kid[y][0])^(y==kid[fy][0]))rotate(x);
32             else rotate(y);
33         }rotate(x);
34     }updata(x);
35 }
36 void Access(int x){
37     int y=0;
38     while(x){
39         Splay(x);kid[x][1]=y;
40         updata(x);
41         y=x;x=fa[x];
42     }
43 }
44 void Cut(int x){
45     Access(x);Splay(x);
46     kid[x][0]=fa[kid[x][0]]=0;
47 }
48 void Link(int x,int y){
49     Cut(x);
50     fa[x]=y;
51     updata(x);
52 }
53 int main(){
54     scanf("%d",&n);
55     int k,x,v;
56     for(int i=1;i<=n;i++){
57         scanf("%d",&v);
58         fa[i]=i+v>n?0:i+v;
59         siz[i]=1;
60     }
61     scanf("%d",&m);
62     for(int i=1;i<=m;i++){
63         scanf("%d%d",&k,&x);x++;
64         if(k==1){
65             Access(x);
66             Splay(x);
67             printf("%d\n",siz[kid[x][0]]+1);
68         }
69         else{
70             scanf("%d",&v);
71             Link(x,x+v>n?0:x+v);
72         }
73     }
74     return 0;
75 }
View Code

 

posted @ 2018-03-19 20:25  鲸头鹳  阅读(117)  评论(2编辑  收藏