传送门
将能跳到的点作为当前点的father,记录子树大小siz,维护动态树即可。
注意:在rotate()时一定要记得pushup(),还有rotate()里好几个ch[ ][ ]修改不要写错了。
*此题还可以用分块解决,后面有空再填坑
#include<bits/stdc++.h>
using namespace std;
const int MAXN=2e5+2;
int n,m;
int siz[MAXN],ch[MAXN][2],fa[MAXN],nxt[MAXN];
bool rev[MAXN];
inline int read() {
int x=0;char c=getchar();
while (c<'0'||c>'9') c=getchar();
while (c>='0'&&c<='9') x=x*10+c-'0',c=getchar();
return x;
}
inline bool isroot(int rt) {
return ch[fa[rt]][1]!=rt&&ch[fa[rt]][0]!=rt;
}
inline void pushup(int rt) {
siz[rt]=siz[ch[rt][0]]+siz[ch[rt][1]]+1;
}
void pushdown(int rt) {
if (!isroot(rt)) pushdown(fa[rt]);
if (rev[rt]) {
rev[rt]=0;
rev[ch[rt][0]]^=1,
rev[ch[rt][1]]^=1;
swap(ch[rt][0],ch[rt][1]);
}
}
inline void rotate(int rt) {
int f=fa[rt],which=(ch[f][1]==rt),r=isroot(f);
ch[f][which]=ch[rt][!which],ch[rt][!which]=f,fa[ch[f][which]]=f;
fa[rt]=fa[f],fa[f]=rt;
if (!r)
ch[fa[rt]][ch[fa[rt]][1]==f]=rt;
pushup(f),pushup(rt);
}
inline void splay(int rt) {
pushdown(rt);
while (!isroot(rt)) {
int f=fa[rt],ff=fa[f];
if (isroot(f))
rotate(rt);
else if ((ch[ff][1]==f)==(ch[f][1]==rt))
rotate(f),rotate(rt);
else
rotate(rt),rotate(rt);
}
}
inline int access(int rt) {
int s=0;
while (rt) {
splay(rt),
ch[rt][1]=s,
s=rt,rt=fa[rt];
}
return s;
}
inline void makeroot(int rt) {
access(rt),splay(rt),rev[rt]^=1;
}
inline void link(int x,int y) {
makeroot(x),fa[x]=y;
}
inline void cut(int x,int y) {
makeroot(x),access(y),splay(y),fa[x]=ch[y][0]=0;
}
int main() {
// freopen("bzoj 2002.in","r",stdin);
memset(rev,false,sizeof(rev));
n=read();
for (register int i=1;i<=n;++i) {
int x=read();
nxt[i]=fa[i]=(x+i>n)?n+1:x+i,
siz[i]=1;
}
siz[n+1]=1;
int m=read();
for (register int i=1;i<=m;++i) {
int flag=read();
if (flag^1) {
int x=read()+1,y=read();
int t=min(x+y,n+1);
cut(x,nxt[x]),link(x,nxt[x]=t);
}
else {
makeroot(n+1);
int x=read()+1;
access(x),splay(x);
printf("%d\n",siz[ch[x][0]]);
}
}
return 0;
}