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
HINT
Source
Splay 启发式合并
Splay启发式合并什么鬼…………
据说分块能水?
第
i
个点向第
很容易想到是一个树形结构,需要新建一个根节点root代表弹飞后指向的点。
设根节点深度为0,那每个点的答案就是它的深度。
支持修改:改变一个点的父亲。
一个link+一个cut即可。
代码:
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<iostream>
using namespace std;
const int SZ = 1000010;
const int INF = 1000000010;
struct node{
node *f,*ch[2];
int sz;
bool rev;
void setc(node *x,int d) { (ch[d] = x) -> f = this; }
int dir() { return f -> ch[1] == this; }
bool isroot() { return f -> ch[0] != this && f -> ch[1] != this; }
void maintain() { sz = ch[0] -> sz + 1 + ch[1] -> sz; }
void pushdown();
}T[SZ], *null, *tree[SZ], *S[SZ];
int Tcnt = 0;
node* newnode()
{
node *k = T + (Tcnt ++);
k -> ch[0] = k -> ch[1] = k -> f = null;
k -> sz = 1;
k -> rev = 0;
return k;
}
void pushrev(node *p) { if(p == null) return ; swap(p -> ch[0],p -> ch[1]); p -> rev ^= 1; }
void node :: pushdown()
{
if(rev) { pushrev(ch[0]); pushrev(ch[1]); rev = 0; }
}
void rotate(node *p)
{
int d = p -> dir();
node *fa = p -> f;
p -> f = fa -> f;
if(!fa -> isroot()) fa -> f -> ch[fa -> dir()] = p;
fa -> ch[d] = p -> ch[d ^ 1];
if(fa -> ch[d] != null) fa -> ch[d] -> f = fa;
p -> setc(fa, d ^ 1);
fa -> maintain(); p -> maintain();
}
int top = 0;
void pushpath(node *p)
{
while(!p -> isroot()) S[++ top] = p,p = p -> f;
S[++ top] = p;
while(top) S[top --] -> pushdown();
}
void splay(node *p)
{
pushpath(p);
while(!p -> isroot())
{
p -> maintain();
if(p -> f -> isroot()) rotate(p);
else
{
if(p -> dir() == p -> f -> dir()) rotate(p -> f),rotate(p);
else rotate(p),rotate(p);
}
}
p -> maintain();
}
void access(node *p)
{
node *last = null;
while(p != null)
{
splay(p);
p -> ch[1] = last; p -> maintain();
last = p;
p = p -> f;
}
}
void toroot(node *p)
{
access(p);
splay(p);
pushrev(p);
}
void link(node *u,node *v)
{
toroot(u);
u -> f = v;
}
void cut(node *u,node *v)
{
toroot(u);
access(v);
splay(v);
v -> ch[0] = u -> f = null;
}
int n;
int ask(node *p)
{
toroot(tree[n + 1]);
access(p);
splay(p);
return p -> sz;
}
int num[SZ];
void init() { null = newnode(); null -> sz = 0; }
int main()
{
init();
scanf("%d",&n);
for(int i = 1;i <= n + 1;i ++) tree[i] = newnode();
for(int i = 1;i <= n;i ++)
{
scanf("%d",&num[i]);
link(tree[i],tree[min(n + 1,i + num[i])]);
}
int m;
scanf("%d",&m);
while(m --)
{
int opt;
scanf("%d",&opt);
if(opt == 1)
{
int pos;
scanf("%d",&pos);
printf("%d\n",ask(tree[pos + 1]) - 1);
}
else
{
int pos,x;
scanf("%d%d",&pos,&x);
pos ++;
cut(tree[pos],tree[min(n + 1,pos + num[pos])]);
num[pos] = x;
link(tree[pos],tree[min(n + 1,pos + num[pos])]);
}
}
return 0;
}