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 }