题目描述
某天,Lostmonkey发明了一种超级弹力装置,为了在他的绵羊朋友面前显摆,他邀请小绵羊一起玩个游戏。游戏一开始,Lostmonkey在地上沿着一条直线摆上n个装置,每个装置设定初始弹力系数ki,当绵羊达到第i个装置时,它会往后弹ki步,达到第i+ki个装置,若不存在第i+ki个装置,则绵羊被弹飞。绵羊想知道当它从第i个装置起步时,被弹几次后会被弹飞。为了使得游戏更有趣,Lostmonkey可以修改某个弹力装置的弹力系数,任何时候弹力系数均为正整数。
题解
容易发现(显然)从一个弹簧只会被弹到一个确定的地方,但一个地方可能会从不同的弹簧弹过来。不觉得这是一棵树么,弹到哪个点上,哪个点就是它的父亲节点。我们新建一个点表示弹出去了,那么次数不就是出发点到这个点的树上距离吗?
再来看看更换弹力系数实际上干了些啥,不就是给他换了个父亲吗。
于是成了 LCT 裸题,动态询问树上两点间的距离。
/*
LCT 求一个点到根的距离方法:
先access(p),Splay(p) 这样p的左子树就是所有在p点上方的点,维护size即可;
*/
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cstdlib>
#include<queue>
#include<vector>
using namespace std;
inline int read()
{
int x=0;char ch=getchar();int t=1;
for(;ch>'9'||ch<'0';ch=getchar()) if(ch=='-') t=-1;
for(;ch>='0'&&ch<='9';ch=getchar()) x=(x<<1)+(x<<3)+(ch-48);
return x*t;
}
#define __ NULL
#define ls son[0]
#define rs son[1]
#define get_son(a) (a->fa->rs==a)
#define get_size(a) (a==__? 0:a->size)
const int N=2e5+20;
struct node{
node* fa;node* son[2];int k;
bool rev,is_root;int size;//要维护size
void clear(){fa=ls=rs=__;rev=0;is_root=1;size=1;k=0;}
}*tr[N];
node pool[N];int cnt;
node* st[N];int h;
inline void updata(node* p){p->size=1+get_size(p->ls)+get_size(p->rs);}
inline void push_down(node* p)
{
if(p==__||p->rev==0) return;
p->rev=0;
if(p->ls!=__)p->ls->rev^=1;
if(p->rs!=__)p->rs->rev^=1;
swap(p->ls,p->rs);
}
inline void rotate(node* p)
{
if(p==__||p->is_root==1) return;
register int k=get_son(p);
register node* q=p->fa;register node* gp=q->fa;
q->son[k]=p->son[k^1];
if(p->son[k^1]!=__) p->son[k^1]->fa=q;p->fa=gp;
if(q->is_root) q->is_root=0,p->is_root=1;
else gp->son[get_son(q)]=p;
q->fa=p;p->son[k^1]=q;
updata(p);updata(q);
}
inline void Splay(node* p)
{
if(p==__)return;
h=1;
st[h]=p;
for(register node* i=p;!i->is_root;st[++h]=(i=i->fa));
while(h) push_down(st[h--]);
for(;!p->is_root;rotate(p)){
if(p->fa->is_root) {rotate(p);break;}
if(get_son(p->fa)==get_son(p)) rotate(p->fa);
else rotate(p);
}
updata(p);
}
inline void access(node* p){
for(register node* pre=__;p!=__;pre=p,p=p->fa){
Splay(p);
if(p->rs!=__) p->rs->is_root=1;
p->rs=pre;if(pre!=__) pre->is_root=0;updata(p);
}
}
inline void m_root(node* p){access(p);Splay(p);p->rev^=1;}
inline void Link(node* p,node* q){m_root(p);p->fa=q;}
inline void split(node* p,node* q){m_root(p);access(q);Splay(q);}
inline void Cut(node* p,node* q) {
split(p,q);
if(q->ls==p) p->fa=q->ls=__,p->is_root=1,updata(q);
}
int n;
inline void Query(node* p)
{
split(tr[n+1],p);
printf("%d\n",get_size(p->ls));
}
int main()
{
n=read();
for(register int i=1;i<=n;i++) tr[i]=&pool[cnt++],tr[i]->clear(),tr[i]->k=read();
tr[n+1]=&pool[cnt++];tr[n+1]->clear();
for(register int i=1;i<=n;i++){
register int nt=tr[i]->k+i;
if(nt>n) nt=n+1;Link(tr[i],tr[nt]);
}
int m=read();register int op;register int x,y;
for(register int i=1;i<=m;i++){
op=read();
if(op==1) Query(tr[read()+1]);
else {
x=read()+1;y=read();
register int nt1=tr[x]->k+x;
if(nt1>n) nt1=n+1;
register int nt2=y+x;
if(nt2>n) nt2=n+1;
if(nt1==nt2) continue;
tr[x]->k=y;
Cut(tr[x],tr[nt1]);
Link(tr[x],tr[nt2]);
}
}
}