【题意】我就不多说了;
【题解】我们把 i+k[ i ] 当作是 i 的父亲,这样就是一个求在一棵树上的点到根节点的路径长度。因为这棵树的形态我们不能随便改变,所以可以用(LCA)动态树来做。
#include<cstdio>
#include<cstring>
#include<cstdlib>
#define null 0
#define MAX 210000
int fa[MAX],left[MAX],right[MAX],size[MAX],t[MAX];
//处理父亲
inline void getfa(int x,int y)
{
if(t[y]==1)
{
t[y]=0;t[x]=1;
}else
{
if(right[fa[y]]==y)right[fa[y]]=x;
else left[fa[y]]=x;
}
fa[x]=fa[y];
}
//左旋
inline void Left_Rotate(int x)
{
int p=fa[x];
getfa(x,p);
size[x]=size[p];
size[p]=size[left[p]]+size[left[x]]+1;
fa[left[x]]=p;
right[p]=left[x];
left[x]=p;
fa[p]=x;
}
//右旋
inline void Right_Rotate(int x)
{
int p=fa[x];
getfa(x,p);
size[x]=size[p];
size[p]=size[right[p]]+size[right[x]]+1;
fa[right[x]]=p;
left[p]=right[x];
right[x]=p;
fa[p]=x;
}
//利用 splay 保持平衡;
void splay(int x)
{
while(t[x]!=1)
{
int p=fa[x];
if(t[p]==1)
{
if(x==left[p])Right_Rotate(x);
else Left_Rotate(x);
break;
}else
if(p==right[fa[p]])
{
if(x==right[p])
{
Left_Rotate(p);
Left_Rotate(x);
}
else {
Right_Rotate(x);
Left_Rotate(x);
}
}else
{
if(x==left[p])
{
Right_Rotate(p);
Right_Rotate(x);
}else{
Left_Rotate(x);
Right_Rotate(x);
}
}
}
}
//实边与虚边的调整(即将从 x 节点到根节点路径上的边都变成实边)
inline void access(int x)
{
splay(x);
int u=fa[x];
size[x]-=size[right[x]];
t[right[x]]=1;
right[x]=null;
while(u!=null){
splay(u);
t[right[u]]=1;
size[u]=size[u]-size[right[u]]+size[x];
right[u]=x;
t[x]=0;
x=u;
u=fa[u];
}
}
void getin(int &x)
{
x=0;char ch=getchar();
while((ch==' ')||(ch=='\n')||(ch=='\r'))ch=getchar();
while((ch!=' ')&&(ch!='\n')&&(ch!='\r'))x=x*10+(int)ch-48,ch=getchar();
}
int main()
{
int n,l,r,m,p;
memset(right,0,sizeof(right));
memset(left,0,sizeof(left));
size[0]=0;fa[0]=0;
getin(n);
for(int i=1;i<=n;i++)
{
getin(p);
if((i+p)<=n)fa[i]=i+p;
else fa[i]=null;
t[i]=size[i]=1;
}
getin(m);
for(;m;m--)
{
getin(l);
if(l==1){
getin(r);r++;
access(r);splay(r);
printf("%d\n",size[left[r]]+1);
}else if(l==2)
{
getin(l),getin(r);l++;
splay(l);
fa[left[l]]=fa[l];
t[left[l]]=1;
//刚开始转移,还是虚边;
size[l]-=size[left[l]];
left[l]=null;
if((l+r)<=n)fa[l]=l+r;
else fa[l]=null;
}
}
return 0;
}