题意:
直线上有一排n个弹力装置,每个弹力装置会将绵羊弹到下ki个弹力装置处;
如果没有了则绵羊被弹飞。。
问每个绵羊被弹了几次弹飞;
可能会修改弹力装置的k值;
n<=200000,m<=100000;
题解:
裸的LCT吧;
所以下面的启发式合并Splay是啥鬼;
有人说这题边有向,和无向边不一样;
然而有个卵区别,把终点作为根不就有向了吗!
反正切了上一题这一题也不难吧;
维护个size之后,把终点作为根再access(x);
这时的Splay就是x弹飞的路线啦,Splay(x)之后x的左子树大小就是答案咯;
其实也是整棵Splay的大小-1,因为x的重儿子在access时砍掉了嘛;
LCT是啥啥的还是戳上一篇。。
代码:
#include<stdio.h>
#include<string.h>
#include<algorithm>
#define N 210000
#define which(x) (ch[fa[x]][1]==x)
using namespace std;
int fa[N],ch[N][2],size[N],to[N],root;
bool rt[N],cov[N];
void Pushup(int x)
{
size[x]=size[ch[x][0]]+size[ch[x][1]]+1;
}
void reverse(int x)
{
swap(ch[x][0],ch[x][1]);
cov[x]^=1;
}
void Pushdown(int x)
{
if(cov[x])
{
reverse(ch[x][0]);
reverse(ch[x][1]);
cov[x]=0;
}
}
void down(int x)
{
if(!rt[x]) down(fa[x]);
Pushdown(x);
}
void Rotate(int x)
{
int f=fa[x];
bool k=which(x);
if(rt[f]) rt[f]^=rt[x]^=1;
else ch[fa[f]][which(f)]=x;
ch[f][k]=ch[x][!k];
ch[x][!k]=f;
fa[ch[f][k]]=f;
fa[x]=fa[f];
fa[f]=x;
size[x]=size[f];
Pushup(f);
}
void Splay(int x)
{
down(x);
while(!rt[x])
{
int f=fa[x];
if(rt[f])
{
Rotate(x);
return ;
}
if(which(x)^which(f))
Rotate(x);
else
Rotate(f);
Rotate(x);
}
}
void access(int x)
{
int y=0;
while(x)
{
Splay(x);
rt[ch[x][1]]=1;
rt[y]=0;
ch[x][1]=y;
Pushup(x);
y=x,x=fa[x];
}
}
void Mtr(int x)
{
access(x);
Splay(x);
reverse(x);
}
void Link(int x,int y)
{
Mtr(x);
fa[x]=y;
}
void Cut(int x,int y)
{
Mtr(x);
access(y);
Splay(x);
ch[x][1]=0,fa[y]=0;
rt[y]=1;
Pushup(x);
}
int Query(int x)
{
Mtr(root);
access(x);
Splay(x);
return size[ch[x][0]];
}
int main()
{
int n,m,i,j,k,x,y,op;
scanf("%d",&n);
root=n+1;
for(i=1;i<=n+1;i++)
rt[i]=1,size[i]=1;
for(i=1;i<=n;i++)
{
scanf("%d",&k);
to[i]=min(i+k,root);
Link(i,to[i]);
}
scanf("%d",&m);
for(i=1;i<=m;i++)
{
scanf("%d",&op);
if(op==1)
{
scanf("%d",&x),x++;
printf("%d\n",Query(x));
}
else
{
scanf("%d%d",&x,&k),x++;
Cut(x,to[x]);
to[x]=min(x+k,root);
Link(x,to[x]);
}
}
return 0;
}