[HNOI2010]Bounce 弹飞绵羊
【题目描述】
某天,Lostmonkey发明了一种超级弹力装置,为了在他的绵羊朋友面前显摆,他邀请小绵羊一起玩个游戏。游戏一开始,Lostmonkey在地上沿着一条直线摆上n个装置,每个装置设定初始弹力系数ki,当绵羊达到第i个装置时,它会往后弹ki步,达到第i+ki个装置,若不存在第i+ki个装置,则绵羊被弹飞。绵羊想知道当它从第i个装置起步时,被弹几次后会被弹飞。为了使得游戏更有趣,Lostmonkey可以修改某个弹力装置的弹力系数,任何时候弹力系数均为正整数。
【输入格式】
第一行包含一个整数n,表示地上有n个装置,装置的编号从0到n-1,接下来一行有n个正整数,依次为那n个装置的初始弹力系数。第三行有一个正整数m,接下来m行每行至少有两个数i、j,若i=1,你要输出从j出发被弹几次后被弹飞,若i=2则还会再输入一个正整数k,表示第j个弹力装置的系数被修改成k。对于10%的数据n,m<=10000,对于100%的数据n<=200000,m<=100000
【输出格式】
对于每个i=1的情况,你都要输出一个需要的步数,占一行。
【样例输入】
4
1 2 1 1
3
1 1
2 1 1
1 1
【样例输出】
2
3
分析
本蒟蒻并不会分块,但是最近学了LCT到可以巨慢的用LCT做
分析题目
设劲度系数为a[i] 那么i可以向i+a[i]连边。 怎么样才算完成能?我们不难看出如果i+a[i]>n则代表飞出那么就可以设一个节点t=n+1; 如果能飞出的话就向t连边
query(x)
将t移到根节点 再access(x)。那么x与y就有一条路径,这条路径就是弹射的过程。
怎么求解呢?
维护一个size 每次都更改size。 splay(x) T[x].size-1就是答案
modify(x,y)
切掉上一条边,再加一条新边。
代码
#include <iostream>
#include <cstdio>
using namespace std;
const int maxn=500000+5;
struct node
{
int size,fa,ch[2]; bool reverse,is_root;
}T[maxn];
int a[maxn];
int n,m,t;
int getson(int x);
void link(int x,int y);
void cut(int x,int y);
void access(int x);
void splay(int x);
void rotate(int x);
void pushdown(int x);
void push(int x);
void pushreverse(int x);
void mroot(int x);
int query(int x);
int main()
{
freopen("bzoj_2002.in","r",stdin);
freopen("bzoj_2002.out","w",stdout);
scanf("%d",&n);
t=n+1;
for(int i=1; i<=n+1; i++)
{
T[i].is_root=true; T[i].fa=T[i].ch[0]=T[i].ch[1]=T[i].reverse=0;
}
for(int i=1; i<=n; i++)
{
int x; scanf("%d",&x);a[i]=x;
if(i+x>n)
{
link(i,t);
}
else link(i,x+i);
}
scanf("%d",&m);
for(int i=1; i<=m; i++)
{
int opt;
scanf("%d",&opt);
if(opt==1)
{
int x;
scanf("%d",&x); x++; printf("%d\n",query(x)-1);
}
else
{
int x,y;
scanf("%d %d",&x,&y); x++;
int aim;
aim=x+a[x]>n? t:x+a[x];
cut(x,aim);
aim=x+y>n? t: x+y; a[x]=y;
link(x,aim);
}
}
return 0;
}
void update(int x)
{
T[x].size=T[T[x].ch[1]].size+T[T[x].ch[0]].size+1;
}
int getson(int x)
{
return T[T[x].fa].ch[1]==x;
}
void pushreverse(int x)
{
if(!x) return;
swap(T[x].ch[0],T[x].ch[1]);
T[x].reverse^=1;
}
void pushdown(int x)
{
if(T[x].reverse)
{
pushreverse(T[x].ch[0]); pushreverse(T[x].ch[1]);
T[x].reverse=false;
}
}
void push(int x)
{
if(!T[x].is_root) push(T[x].fa);
pushdown(x);
}
void rotate(int x)
{
int son=getson(x),fa=T[x].fa; int g=T[fa].fa;
T[fa].ch[son]=T[x].ch[son^1]; T[fa].fa=x; T[x].fa=g;
if(T[x].ch[son^1]) T[T[x].ch[son^1]].fa=fa;
T[x].ch[son^1]=fa;
if(!T[fa].is_root) T[g].ch[T[g].ch[1]==fa]=x;
else T[x].is_root=true,T[fa].is_root=false;
update(fa); update(x);
}
void splay(int x)
{
push(x);
for(int fa; !T[x].is_root; rotate(x))
{
if(!T[fa=T[x].fa].is_root) rotate(getson(x)==getson(fa)? fa: x);
}
}
void access(int x)
{
int y=0;
do
{
splay(x);
T[T[x].ch[1]].is_root=true;
T[T[x].ch[1]=y].is_root=false;
update(x);
x=T[y=x].fa;
}while(x);
}
void mroot(int x)
{
access(x); splay(x); pushreverse(x);
}
void link(int x,int y)
{
mroot(x); T[x].fa=y;
}
void cut(int x,int y)
{
mroot(x); access(y); splay(y);
T[x].is_root=true; T[x].fa=T[y].ch[0]=0;
}
int query(int x)
{
mroot(t); access(x); splay(x);
return T[x].size;
}