2002: [Hnoi2010]Bounce 弹飞绵羊
Time Limit: 10 Sec Memory Limit: 259 MB
Submit: 12905 Solved: 6578
[Submit][Status][Discuss]
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,但网上有很多种不同的做法。。。我是没有用换根直接做。注意编号是0~n-1。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <algorithm>
#include <queue>
#include <vector>
#include <map>
#include <string>
#include <cmath>
#include <sstream>
#define min(a, b) ((a) < (b) ? (a) : (b))
#define max(a, b) ((a) > (b) ? (a) : (b))
#define abs(a) ((a) < 0 ? (-1 * (a)) : (a))
template<class T>
inline void swap(T &a, T &b)
{
T tmp = a;a = b;b = tmp;
}
inline void read(int &x)
{
x = 0;char ch = getchar(), c = ch;
while(ch < '0' || ch > '9') c = ch, ch = getchar();
while(ch <= '9' && ch >= '0') x = x * 10 + ch - '0', ch = getchar();
if(c == '-') x = -x;
}
const int INF = 0x3f3f3f3f;
const int MAXN = 200000 + 10;
int ch[MAXN][2], fa[MAXN], size[MAXN], lazy[MAXN];
inline int son(int x){return x == ch[fa[x]][1];}
inline void pushup(int x){size[x] = size[ch[x][0]] + size[ch[x][1]] + 1;}
inline int isroot(int x){return ch[fa[x]][0] != x && ch[fa[x]][1] != x;}
void rotate(int x)
{
int y = fa[x], z = fa[y], b = son(x), c = son(y), a = ch[x][!b];
if(!isroot(y) && z) ch[z][c] = x; fa[x] = z;
if(a) fa[a] = y; ch[y][b] = a;
ch[x][!b] = y, fa[y] = x;
pushup(y), pushup(x);
}
void splay(int x)
{
while(!isroot(x))
{
int y = fa[x], z = fa[y];
if(!isroot(y))
if(son(x) == son(y)) rotate(y);
else rotate(x);
rotate(x);
}
}
inline void access(int x){for(int y = 0;x;y = x, x = fa[x])splay(x), ch[x][1] = y, pushup(x);}
inline void link(int x, int y){access(y), splay(y), fa[x] = y, pushup(y);}//把x连到y上,y为父亲
inline void cut(int x, int y){access(x), splay(y), fa[x] = ch[y][1] = 0, pushup(x);}//y为x的父亲
int n,m,tmp1,tmp2,tmp3,num[MAXN];
int main()
{
read(n);
register int i;
for(i = 1;i <= n;++ i)
read(num[i]), fa[i] = min(n + 1, i + num[i]), size[i] = 1;
size[n + 1] = 1;
read(m);
for(i = 1;i <= m;++ i)
{
read(tmp1), read(tmp2);++ tmp2;
if(tmp1 == 1)
{
access(tmp2);
splay(tmp2);
printf("%d\n", size[ch[tmp2][0]]);
}
else read(tmp3), cut(tmp2, min(tmp2 + num[tmp2], n + 1)), link(tmp2, min(n + 1, tmp2 + tmp3)), num[tmp2] = tmp3;
}
return 0;
}