[HNOI2010]弹飞绵羊

Posted Z-Y-Y-S

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[HNOI2010]弹飞绵羊相关的知识,希望对你有一定的参考价值。

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

先建树,如果i+k大于n,就和n+1,建边表示弹出,否则和i+k建边

建树用LCT的link操作

修改就cut操作删掉旧边,加上新边

查询时,把n+1变为树根,把x到n+1都变为实根

查询路径上节点数-1输出

splay维护size,因为总是只有一颗完整的树,所以不需要判断cut和link操作的可行性

  1 #include<iostream>
  2 #include<cstdio>
  3 #include<cstring>
  4 #include<algorithm>
  5 #include<cmath>
  6 using namespace std;
  7 int size[200005],ch[200005][2],rev[200005],pre[200005],isrt[200005],n,m,k[200005];
  8 void pushup(int o)
  9 {
 10   if (!o) return;
 11   size[o]=size[ch[o][0]]+size[ch[o][1]]+1;
 12 }
 13 void pushdown(int o)
 14 {
 15   if (!o) return;
 16   if (rev[o])
 17     {
 18       int ls=ch[o][0],rs=ch[o][1];
 19       rev[ls]^=1;
 20       swap(ch[ls][0],ch[ls][1]);
 21       rev[rs]^=1;
 22       swap(ch[rs][0],ch[rs][1]);
 23       rev[o]=0;
 24     }
 25 }
 26 void push(int o)
 27 {
 28   if (isrt[o]==0) push(pre[o]);
 29   pushdown(o);
 30 }
 31 void rotate(int o,bool kind)
 32 {
 33   int p=pre[o];
 34   ch[p][!kind]=ch[o][kind];pre[ch[o][kind]]=p;
 35   if (isrt[p]) isrt[p]=0,isrt[o]=1;
 36   else ch[pre[p]][ch[pre[p]][1]==p]=o;
 37   pre[o]=pre[p];
 38   ch[o][kind]=p;pre[p]=o;
 39   pushup(p);pushup(o);
 40 }
 41 void splay(int o)
 42 {
 43   push(o);
 44   while (isrt[o]==0)
 45     {
 46       if (isrt[pre[o]])
 47     rotate(o,ch[pre[o]][0]==o);
 48       else
 49     {
 50       int p=pre[o],kind=ch[pre[p]][0]==p;
 51       if (ch[p][kind]==o)
 52         rotate(o,!kind),rotate(o,kind);
 53       else rotate(p,kind),rotate(o,kind);
 54     }
 55     }
 56 }
 57 void access(int o)
 58 {
 59   int y=0;
 60   while (o)
 61     {
 62       splay(o);
 63       isrt[ch[o][1]]=1;
 64       isrt[ch[o][1]=y]=0;
 65       pushup(o);
 66       y=o;o=pre[o];
 67     }
 68 }
 69 void makeroot(int o)
 70 {
 71   access(o);
 72   splay(o);
 73   rev[o]^=1;
 74   swap(ch[o][0],ch[o][1]);
 75 }
 76 void link(int x,int y)
 77 {
 78   makeroot(x);
 79   pre[x]=y;
 80 }
 81 void cut(int x,int y)
 82 {
 83   makeroot(x);
 84   access(y);splay(y);
 85   ch[y][0]=0;pre[x]=0;
 86   isrt[x]=1;
 87   pushup(y);
 88 }
 89 int main()
 90 {int i,c,x,y,st,ed;
 91   cin>>n;
 92   for (i=1;i<=n+1;i++)
 93     isrt[i]=1,size[i]=1;
 94   for (i=1;i<=n;i++)
 95     {
 96       scanf("%d",&k[i]);
 97       if (i+k[i]>n) link(i,n+1);
 98       else link(i,i+k[i]);
 99     }
100   cin>>m;
101   for (i=1;i<=m;i++)
102     {
103       scanf("%d",&c);
104       if (c==1)
105     {
106       scanf("%d",&x);x++;
107       makeroot(n+1);
108       access(x);
109       splay(x);
110       printf("%d\n",size[x]-1);
111     }
112       else
113     {
114       scanf("%d%d",&x,&y);x++;
115       if (k[x]+x>n) st=n+1;
116       else st=k[x]+x;
117       if (y+x>n) ed=n+1;
118       else ed=y+x;
119       k[x]=y;
120       if (st!=ed)
121         {
122           cut(x,st);
123           link(x,ed);
124         }
125     }
126     }
127 }

 

以上是关于[HNOI2010]弹飞绵羊的主要内容,如果未能解决你的问题,请参考以下文章

[HNOI2010]弹飞绵羊

[HNOI2010]弹飞绵羊

HNOI2010 弹飞绵羊

bzoj 2002: [Hnoi2010]Bounce 弹飞绵羊

BZOJ2002: [Hnoi2010]Bounce 弹飞绵羊

2002: [Hnoi2010]Bounce 弹飞绵羊