bzoj2002 弹飞绵羊

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的情况,你都要输出一个需要的步数,占一行。

用块状树维护由跳跃一次后位置到跳跃前位置连边构成的有根树。

每操作O(n0.5)次重构整棵树

均摊时间复杂度O(n1.5)

#include<cstdio>
#include<cmath>
int n,m,rt;
int cs,cb,tt=,cb2;
int fa[],fw[],v[],dep[],top[];
int enx[],epv[],ew[],ep;
inline int min(int a,int b){
return a<b?a:b;
}
void addedge(int a,int b){
fa[b]=a;
ew[ep]=b;
enx[epv[ep]=epv[a]]=ep;
enx[ep]=a;
fw[b]=epv[a]=ep++;
}
void deledge(int a){
int x=fw[a],pv=epv[x];
epv[enx[pv]=enx[x]]=pv;
}
int getdep(int x){
int ans=-;
while(x){
ans+=dep[x];
x=fa[top[x]];
}
return ans;
}
void build(int w){
++cs;
if(cs<=cb)top[w]=top[fa[w]],dep[w]=dep[fa[w]]+;
else cs=,top[w]=w,dep[w]=;
for(int i=enx[w],u=ew[i];u=ew[i];i=enx[i])build(u);
}
int tp,tpn,dp;
void dfs(int w){
if(top[w]!=tp)return;
top[w]=tpn;
dep[w]=dp;
++dp;
for(int i=enx[w],u=ew[i];u=ew[i];i=enx[i])dfs(u);
--dp;
}
int main(){
scanf("%d",&n);
cb=sqrt(n);
cb2=cb*;
rt=n+;
for(int i=;i<=n;i++)scanf("%d",v+i);
for(int i=;i<=rt;i++)enx[i]=epv[i]=i;ep=rt+;
for(int i=;i<=n;i++)addedge(min(i+v[i],rt),i);
scanf("%d",&m);
cs=cb,build(rt);
while(m--){
int op,a,b;
scanf("%d",&op);
if(op==){
scanf("%d%d",&a,&b);++a;
v[a]=b;
deledge(a);
addedge(min(a+v[a],rt),a);
tp=top[a],tpn=a,dp=,dfs(a);
if(++tt>cb2)cs=cb,build(rt),tt=;
}else{
int vans;
scanf("%d",&a);++a;
printf("%d\n",vans=getdep(a));
}
}
return ;
}
上一篇:SOAP,RESTFull以及RPC的认识


下一篇:2010-2011 ACM-ICPC, NEERC, Moscow Subregional Contest Problem F. Finance 模拟题