题目:
题解:
这就是一道LCT的裸题啦
这里的f[x]表示在辅助树中x的father,a[x]则表示在原树中x的father
询问的时候先将n+1换成根,然后access x,然后将x splay到根,这样x左子树的大小就是答案
代码:
#include <iostream>
#include <cstring>
#include <cstdio>
using namespace std;
const int N=200005;
int size[N],deltaz[N],f[N],stack[N],n,a[N],ch[N][2;
//请同学们不要盲目复制,这里并不是博主设坎,而是只要加上]就没有高亮代码了!
int get(int x){return ch[f[x]][1]==x;}
void updata(int now){size[now]=1+size[ch[now][0]]+size[ch[now][1]];}
void pushdown(int now)
{
if (deltaz[now])
{
swap(ch[now][0],ch[now][1]);
deltaz[ch[now][0]]^=1; deltaz[ch[now][1]]^=1;
deltaz[now]=0;
}
}
bool Is_root(int x){return ch[f[x]][0]!=x && ch[f[x]][1]!=x;}
void rotate(int x)
{
int old=f[x],oldf=f[old],which=get(x);bool gen=Is_root(old);
ch[old][which]=ch[x][which^1]; f[ch[x][which^1]]=old;
ch[x][which^1]=old; f[old]=x;
f[x]=oldf; if (!gen) ch[oldf][ch[oldf][1]==old]=x;//一定要提前判断gen,如果在这里判断的话f[old]已经转变
updata(old);
updata(x);
}
void splay(int x)
{
int top=0,i;
for (i=x;!Is_root(i);i=f[i]) stack[++top]=i;
stack[++top]=i;
for (i=top;i>=1;i--) pushdown(stack[i]);
for (;!Is_root(x);rotate(x))
if (!Is_root(f[x])) rotate(get(f[x])==get(x)?f[x]:x);
}
void access(int x)
{
int t=0;
for (;x;t=x,x=f[x])
{
splay(x);
ch[x][1]=t;
}
}
void reverse(int x)
{
access(x);
splay(x);
deltaz[x]^=1;
}
void Link(int x,int y)
{
reverse(x);
f[x]=y;
splay(x);
}
void Cut(int x,int y)
{
reverse(x); access(y);
splay(y);
ch[y][0]=f[x]=0;
}
int qurry(int x)
{
reverse(n+1);
access(x);
splay(x);
return size[ch[x][0]];
}
int main()
{
scanf("%d",&n);
for (int i=1;i<=n;i++)
{
int x;
scanf("%d",&x);
if (x+i<=n) a[i]=x+i;else a[i]=n+1;
f[i]=a[i];
size[i]=1;
}
size[n+1]=1;
int m;
scanf("%d",&m);
while(m--)
{
int id,x,v;
scanf("%d",&id);
if (id==1)
{
scanf("%d",&x);
x++; printf("%d\n",qurry(x));
}
else
{
scanf("%d%d",&x,&v);
x++;
Cut(x,a[x]);
if (x+v<=n) a[x]=x+v;
else a[x]=n+1;
Link(x,a[x]);
}
}
}