【洛谷P3203】[HNOI2010]弹飞绵羊【LCT】
Solution
我们把一次从\(i\)向后弹到\(i+k_i\)看作是连了一条边,如果\(i+k_i>n\)也就是被弹飞了,我们就认为被弹到了一个特殊节点\(n+1\)
于是就直接维护\(Splay\)上子树的\(siz\),查询从\(x\)起步,就拉出从\(x\)到\(n+1\)的\(Splay\),将\(n+1\)置为根,然后输出\(n+1\)维护的\(siz\)即可
更改弹力系数就是先\(cut\)再\(link\)
Code
#include<bits/stdc++.h>
using namespace std;
const int N=4e5+10;
int n,siz[N],ch[N][2],fa[N],rev[N];
inline bool which(int x){return ch[fa[x]][1]==x;}
inline void pushup(int x){
siz[x]=siz[ch[x][0]]+siz[ch[x][1]]+1;
}
inline bool isroot(int x){return ch[fa[x]][0]!=x&&ch[fa[x]][1]!=x;}
inline void rever(int x){
swap(ch[x][0],ch[x][1]);
rev[x]^=1;
}
inline void pushdown(int x){
if(!rev[x]) return ;
if(ch[x][0]) rever(ch[x][0]);
if(ch[x][1]) rever(ch[x][1]);
rev[x]=0;
}
inline void Rotate(int x){
int y=fa[x],z=fa[y],wx=which(x),wy=which(y);
if(!isroot(y)) ch[z][wy]=x;fa[x]=z;
ch[y][wx]=ch[x][wx^1];
if(ch[y][wx]) fa[ch[y][wx]]=y;
ch[x][wx^1]=y;fa[y]=x;
pushup(y);
}
int stk[N],top;
inline void Splay(int x){
int now=x;
stk[top=1]=now;
while(!isroot(now)) now=fa[now],stk[++top]=now;
while(top) pushdown(stk[top--]);
while(!isroot(x)){
int y=fa[x];
if(!isroot(y)){
if(which(x)==which(y)) Rotate(y);
else Rotate(x);
}Rotate(x);
}
pushup(x);
}
inline void access(int x){
for(int last=0;x;last=x,x=fa[x])
Splay(x),ch[x][1]=last,pushup(x);
}
inline void makeroot(int x){
access(x);Splay(x);
rever(x);
}
inline int findroot(int x){
access(x);Splay(x);
while(ch[x][0]) pushdown(x),x=ch[x][0];
Splay(x);
return x;
}
inline void split(int x,int y){
makeroot(x);access(y);
Splay(y);
}
inline void link(int x,int y){
makeroot(x);
fa[x]=y;
}
inline void cut(int x,int y){
split(x,y);
fa[x]=ch[y][0]=0;
pushup(y);
}
int v[N],m,cnt=0;
int main(){
scanf("%d",&n);
for(int i=1;i<=n;++i){
scanf("%d",&v[i]);
v[i]+=i;
if(v[i]>n) v[i]=n+1;
link(i,v[i]);
}
scanf("%d",&m);
for(int i=1;i<=m;++i){
int op,x,y;
scanf("%d%d",&op,&x);++x;
if(op==1){
split(x,n+1);
printf("%d\n",siz[n+1]-1);
}
else{
scanf("%d",&y);
int nw=y+x;if(nw>n) nw=n+1;
if(nw==v[x]) continue;
else cut(x,v[x]),v[x]=nw,link(x,v[x]);
}
}
return 0;
}