题目大意: 你有一排弹力装置,对于第 i i i 个弹力装置,它可以把在它上面的绵羊弹到 i + a [ i ] i+a[i] i+a[i] 的位置,假如这个位置不存在,则成这个绵羊被弹飞了。现在有两种操作: 1、更改某个装置的弹力; 2、询问绵羊从某个位置出发会被弹几次之后才会被弹飞。
题解
比较模板的 L C T LCT LCT 了,让每个 i i i 向 i + a [ i ] i+a[i] i+a[i] 连边,让 i + a [ i ] i+a[i] i+a[i] 成为 i i i 的父亲,那么从点 i i i 出发,答案就是 i i i 到根节点要经过多少个节点。
但是众所周知, L C T LCT LCT 这个家伙随手就会改变根节点,所以我们每次询问的时候都得先把最后的那个节点提上来成为根节点。但是我们并不可能知道谁是最后的那个节点,所以我们使那些 i + a [ i ] i+a[i] i+a[i] 不存在的 i i i 节点都向 n + 1 n+1 n+1 位置连一条边,然后每次询问的时候把 n + 1 n+1 n+1 提上来就好了,但是答案要 − 1 -1 −1。
代码如下:
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
#define maxn 200010
int n,m;
int a[maxn];
struct node{
int size,lazy;
node *zuo,*you,*fa;
node():size(1),lazy(0),zuo(NULL),you(NULL),fa(NULL){}
void check()
{
size=1;
if(zuo!=NULL)size+=zuo->size;
if(you!=NULL)size+=you->size;
}
void pushdown()
{
if(lazy)
{
lazy=0;
swap(zuo,you);
if(zuo!=NULL)zuo->lazy^=1;
if(you!=NULL)you->lazy^=1;
}
}
bool notroot(){return fa!=NULL&&(fa->zuo==this||fa->you==this);}
};
node *root[maxn];
node *zhan[maxn];
int t;
void rotate(node *x)
{
node *fa=x->fa,*gfa=fa->fa;
if(fa->zuo==x)
{
fa->zuo=x->you;
if(x->you!=NULL)x->you->fa=fa;
x->you=fa;
}
else
{
fa->you=x->zuo;
if(x->zuo!=NULL)x->zuo->fa=fa;
x->zuo=fa;
}
fa->fa=x;x->fa=gfa;
if(gfa!=NULL&&gfa->zuo==fa)gfa->zuo=x;
if(gfa!=NULL&&gfa->you==fa)gfa->you=x;
fa->check();x->check();
}
#define witch(x) (x->fa->zuo==x)
void splay(node *x)
{
node *now=x;
zhan[++t]=now;
while(now->notroot())zhan[++t]=now=now->fa;
while(t)zhan[t--]->pushdown();
while(x->notroot())
{
if(x->fa->notroot()&&witch(x)==witch(x->fa))rotate(x->fa),rotate(x);
else rotate(x);
}
}
void access(node *x)
{
for(node *y=NULL;x!=NULL;y=x,x=x->fa)
splay(x),x->you=y,x->check();
}
void makeroot(node *x)
{
access(x);splay(x);
x->lazy^=1;x->pushdown();
}
void link(node *x,node *y)
{
makeroot(x);
x->fa=y;
}
void del(node *x,node *y)
{
makeroot(y);access(x);splay(y);
y->you=x->fa=NULL;
}
int main()
{
scanf("%d",&n);
for(int i=1;i<=n+1;i++)
root[i]=new node();
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
if(i+a[i]<=n)link(root[i],root[i+a[i]]);
else link(root[i],root[n+1]);
}
scanf("%d",&m);
for(int i=1,id,x,y;i<=m;i++)
{
scanf("%d %d",&id,&x);x++;
if(id==1)makeroot(root[n+1]),access(root[x]),splay(root[n+1]),printf("%d\n",root[n+1]->size-1);
else
{
scanf("%d",&y);
if(x+a[x]<=n)del(root[x],root[x+a[x]]);
else del(root[x],root[n+1]);
a[x]=y;
if(x+a[x]<=n)link(root[x],root[x+a[x]]);
else link(root[x],root[n+1]);
}
}
}