bzoj 2002: [Hnoi2010]Bounce 弹飞绵羊

Description

某天,Lostmonkey发明了一种超级弹力装置,为了在他的绵羊朋友面前显摆,他邀请小绵羊一起玩个游戏。游戏一开始,Lostmonkey在地上沿着一条直线摆上n个装置,每个装置设定初始弹力系数ki,当绵羊达到第i个装置时,它会往后弹ki步,达到第i+ki个装置,若不存在第i+ki个装置,则绵羊被弹飞。绵羊想知道当它从第i个装置起步时,被弹几次后会被弹飞。为了使得游戏更有趣,Lostmonkey可以修改某个弹力装置的弹力系数,任何时候弹力系数均为正整数。

Input

第一行包含一个整数n,表示地上有n个装置,装置的编号从0到n-1,接下来一行有n个正整数,依次为那n个装置的初始弹力系数。第三行有一个正整数m,接下来m行每行至少有两个数i、j,若i=1,你要输出从j出发被弹几次后被弹飞,若i=2则还会再输入一个正整数k,表示第j个弹力装置的系数被修改成k。对于20%的数据n,m<=10000,对于100%的数据n<=200000,m<=100000

Output

对于每个i=1的情况,你都要输出一个需要的步数,占一行。

Sample Input

4
1 2 1 1
3
1 1
2 1 1
1 1

Sample Output

2
3

 题解:

算是简单的吧,可以用把每个弹簧看作一个点,然后LCT维护连通性即可.

如果i+a[i]>n就将i连向n+1 反之连在i+a[i]上.

修改就是先cut再link

答案就是将n+1旋到根 并且把询问点和n+1放到同一Splay中 , 深度比它小的点的个数为答案,然后显然为左子树大小

但是有个问题:gdb的时候并没有发现reserve的作用...于是发现确实没卵用..只不过修改操作要稍作变化

个人浅薄的理解为:mroot操作只是为了在cut得时候把不相关的连在一起,而这题只是cut与原父亲的连边 所以不必mroot

1RE :rotate都打错好多遍,果然还是巨水

  1 #include <algorithm>
  2 #include <iostream>
  3 #include <cstdlib>
  4 #include <cstring>
  5 #include <cstdio>
  6 #include <cmath>
  7 using namespace std;
  8 const int N=200005;
  9 int ch[N][2],size[N],fa[N];bool rev[N],rt[N];
 10 int gi(){
 11     int str=0;char ch=getchar();
 12     while(ch>'9' || ch<'0')ch=getchar();
 13     while(ch>='0' && ch<='9')str=(str<<1)+(str<<3)+ch-48,ch=getchar();
 14     return str;
 15 }
 16 void updata(int r){
 17     if(!r)return ;
 18     swap(ch[r][0],ch[r][1]);
 19     rev[r]^=1;
 20 }
 21 void pushdown(int r){
 22     if(!rev[r])return ;
 23     updata(ch[r][0]);updata(ch[r][1]);
 24     rev[r]=0;
 25 }
 26 void upsize(int r){
 27     if(r)
 28     size[r]=size[ch[r][1]]+size[ch[r][0]]+1;
 29 }
 30 void rotate(int r){
 31     int y=fa[r];bool t=(ch[y][1]==r);
 32     ch[y][t]=ch[r][!t];
 33     ch[r][!t]=y;
 34     fa[ch[y][t]]=y;
 35     fa[r]=fa[y];
 36     if(rt[y])
 37         rt[y]=false,rt[r]=true;
 38     else
 39         ch[fa[y]][ch[fa[y]][1]==y]=r;
 40     fa[y]=r;
 41     upsize(y);upsize(r);
 42 }
 43 void Push(int r){
 44     if(!rt[r] && r)Push(fa[r]);
 45     pushdown(r);
 46 }
 47 void splay(int r){
 48     Push(r);
 49     while(!rt[r]){
 50         int y=fa[r],yy=fa[y];
 51         if(rt[y])
 52             rotate(r);
 53         if((ch[yy][1]==y)==(ch[y][1]==r))rotate(y),rotate(r);
 54         else rotate(r),rotate(r);
 55     }
 56     pushdown(r);upsize(r);
 57 }
 58 void access(int x){
 59     int y=0;
 60     do{
 61         splay(x);
 62         rt[ch[x][1]]=true;rt[ch[x][1]=y]=false;
 63         upsize(x);
 64         x=fa[y=x];
 65     }while(x);
 66 }
 67 void mroot(int x){
 68     access(x);
 69     splay(x);
 70     updata(x);
 71 }
 72 void link(int x,int y){
 73     mroot(x);fa[x]=y;upsize(y);
 74 }
 75 void cut(int x,int y){
 76     mroot(x);access(y);splay(y);
 77     pushdown(y);
 78     fa[x]=ch[y][0]=0;rt[x]=true;
 79     upsize(y);
 80 }
 81 int n,m,a[N];
 82 void query(int x){
 83     mroot(n+1);
 84     access(x);
 85     splay(x);
 86     printf("%d
",size[ch[x][0]]);
 87 }
 88 void change(int x,int to){
 89     if(x+a[x]<=n)cut(x,x+a[x]);
 90     else cut(x,n+1);
 91     a[x]=to;
 92     if(x+a[x]<=n)link(x,x+a[x]);
 93     else link(x,n+1);
 94 }
 95 int main()
 96 {
 97     freopen("bzoj_2002.in","r",stdin);
 98     freopen("bzoj_2002.out","w",stdout);
 99     int x,y,z;
100     n=gi();rt[0]=true;
101     for(int i=1;i<=n+1;i++)size[i]=1,rt[i]=true;
102     for(int i=1;i<=n;i++){
103         a[i]=gi();
104          if(i+a[i]<=n)link(i,i+a[i]);
105           else link(i,n+1);
106     }
107     m=gi();
108     while(m--){
109         x=gi();y=gi();y++;
110         if(x==1)query(y);
111         else z=gi(),change(y,z);
112     }
113     return 0;
114 }
原文地址:https://www.cnblogs.com/Yuzao/p/7280640.html