【题目描述】
某天, L o s t m o n k e y Lostmonkey Lostmonkey发明了一种超级弹力装置,为了在他的绵羊朋友面前显摆,他邀请小绵羊一起玩个游戏。游戏一开始, L o s t m o n k e y Lostmonkey Lostmonkey在地上沿着一条直线摆上 n n n个装置,每个装置设定初始弹力系数 k i ki ki,当绵羊达到第 i i i个装置时,它会往后弹 k i ki ki步,达到第 i + k i i+ki i+ki个装置,若不存在第 i + k i i+ki i+ki个装置,则绵羊被弹飞。绵羊想知道当它从第 i i i个装置起步时,被弹几次后会被弹飞。为了使得游戏更有趣, L o s t m o n k e y Lostmonkey Lostmonkey可以修改某个弹力装置的弹力系数,任何时候弹力系数均为正整数。
【输入格式】
第一行包含一个整数 n n n,表示地上有 n n n个装置,装置的编号从 0 0 0到 n − 1 n-1 n−1。
接下来一行有 n n n个正整数,依次为那 n n n个装置的初始弹力系数。
第三行有一个正整数 m m m,
接下来 m m m行每行至少有两个数 i i i、 j j j,若 i = 1 i=1 i=1,你要输出从 j j j出发被弹几次后被弹飞,若 i = 2 i=2 i=2则还会再输入一个正整数 k k k,表示第 j j j个弹力装置的系数被修改成k。
【输出格式】
对于每个 i = 1 i=1 i=1的情况,你都要输出一个需要的步数,占一行。
S a m p l e    I n p u t Sample\;Input SampleInput
4
1 2 1 1
3
1 1
2 1 1
1 1
S a m p l e    O u t p u t Sample\;Output SampleOutput
2
3
【题意分析】
题目保证每只绵羊只会往后弹,弹到后面没有了就直接弹飞。那么对于被弹飞,可以理解成弹到了第 n + 1 n+1 n+1个点。(虚构的一个节点)
输入的时候,设第 x x x个点设置成往后弹 a [ x ] a[x] a[x],那么如果 x + a [ x ] > n x+a[x] > n x+a[x]>n就 l i n k ( x , x + a [ x ] ) link~(x,x+a[x]) link (x,x+a[x]),否则 l i n k ( x , n + 1 ) link~(x,n+1) link (x,n+1)(被弹飞)
操作的时候,如果是修改,先判断要修改的点连的是 n + 1 n+1 n+1还是 x + a [ x ] x+a[x] x+a[x],先 c u t cut cut,然后跟输入时差不多,判断之后再 l i n k link link。别忘了修改劲度系数!!(此处WA*1)
如果是询问,那就 a c c e s s ( n + 1 ) access~(n+1) access (n+1), s p l a y ( n + 1 ) splay~(n+1) splay (n+1),然后输出 s i z e [ n + 1 ] − 1 size[n+1]-1 size[n+1]−1。
Code:
#include
#include
#include
#include
#include
#include
#include
#include
#define MAXN 500000
using namespace std;
int son[MAXN][2],father[MAXN],size[MAXN],lazy[MAXN];
int a[MAXN],stack[MAXN],n,q;
namespace Link_Cut_Tree{
inline bool isroot (int x){
return !(son[father[x]][0] == x || son[father[x]][1] == x);
}//是否为根
inline void pushup (int x){
size[x] = 1;
if (son[x][0])size[x] += size[son[x][0]];
if (son[x][1])size[x] += size[son[x][1]];
}//更新size
inline void pushdown (int x){
if (lazy[x]){
swap (son[x][0],son[x][1]);
if (son[x][0])lazy[son[x][0]] ^= 1;
if (son[x][1])lazy[son[x][1]] ^= 1;
lazy[x] = 0;
}
}
inline void rotate (int x){
int y = father[x],z = father[y];
int k = son[y][1] == x,kk = son[z][1] == y;
if (!isroot (y))son[z][kk] = x;
father[x] = z;
son[y][k] = son[x][k^1];
father[son[x][k^1]] = y;
son[x][k^1] = y;
father[y] = x;
pushup (y); pushup (x);
}
inline void splay (int x){
int top = 0;
stack[++top] = x;
for (register int i = x;!isroot (i);i = father[i])
stack[++top] = father[i];
for (register int i = top;i;i--)
pushdown (stack[i]);
while (!isroot (x)){
int y = father[x],z = father[y];
if (!isroot (y))
(son[y][1] == x) ^ (son[z][1] == y)
? rotate (x) : rotate (y);
rotate (x);
}
pushup (x);
}
inline void access (int x){
for (register int y = 0;x;y = x,x = father[x]){
splay (x);
son[x][1] = y;
pushup (x);
}
}
inline int findroot (int x){
access (x);
splay (x);
while (son[x][0]){
pushdown (son[x][0]);
x = son[x][0];
}
return x;
}
inline void makeroot (int x){
access (x);
splay (x);
lazy[x] ^= 1;
}
inline void link (int x,int y){
makeroot (x);
father[x] = y;
}
inline void cut (int x,int y){
makeroot (x);
access (y);
splay (y);
son[y][0] = father[x] = 0;
pushup (y);
}
inline int query (int x,int y){
makeroot (x);
access (y);
splay (y);
return size[y] - 1;
}
}using namespace Link_Cut_Tree;
int main (){
scanf ("%d",&n);
for (register int i = 1;i <= n+1;i++)
size[i] = 1;
for (register int i = 1;i <= n;i++){
int x;
scanf ("%d",&x);
(i+x <= n)
? link (i,i+x) : link (i,n+1);
a[i] = x;
}
scanf ("%d",&q);
while (q--){
int type;
scanf ("%d",&type);
if (type == 1){
int x;
scanf ("%d",&x); x++;
printf ("%d\n",query (x,n+1));
}
if (type == 2){
int x,y;
scanf ("%d%d",&x,&y); x++;
(x+a[x] <= n)
? cut (x,x+a[x]) : cut (x,n+1);
(x+y <= n)
? link (x,x+y) : link (x,n+1);
a[x] = y;
}
}
return 0;
}