题目大意:给出一个森林,支持两个操作:修改边,输出点到所在树的根的距离
LCT裸题。操作挺少的,只有Link和Cut操作(所以和到一起写了),维护一下Size即可。
#include <cstdio>
#define N 200005
using namespace std;
struct Node{
Node *ch[2],*pa;
int s;
void maintain(){s=ch[0]->s+ch[1]->s+1;}
int dir(){return pa->ch[0]==this ? 0 : pa->ch[1]==this ? 1 : -1; }//判断当前点与父亲的关系
Node();
}*null=new Node();
Node p[N];
Node :: Node(){pa=ch[0]=ch[1]=null; s=null?1:0;}
void Rotate(Node* o,int d){
Node* k=o->ch[d^1]; int d2;
o->ch[d^1]=k->ch[d]; k->ch[d]->pa=o;
k->ch[d]=o;
o->maintain(); k->maintain();
if(~(d2=o->dir())) o->pa->ch[d2]=k;
k->pa=o->pa; o->pa=k;
}
void Splay(Node *o){
Node* p; int d;
while(~(d=o->dir())){
p=o->pa;
if(p->dir()==d) Rotate(p->pa,d^1);
Rotate(o->pa,d^1);
}
return ;
}
void Access(Node* o){//将o点到根的路径设置为“重链”
Node* p=null;
while(o!=null) {
Splay(o);
o->ch[1]=p; o->maintain();
p=o; o=o->pa;
}
return ;
}
void Link(Node* x,Node* y){
Access(x); Splay(x);
x->ch[0]->pa=null;
x->ch[0]=null; x->maintain();//Cut操作
x->pa=y;
return ;
}
int main(){
int n;
scanf("%d",&n);
null->ch[0]=null->ch[1]=null->pa=null;
for(int i=1;i<=n;i++){
int x;
scanf("%d",&x);
if(i+x<=n) p[i].pa=&p[i+x];
}
int m;
scanf("%d",&m);
while(m--){
int mode;
scanf("%d",&mode);
if(mode==1){
int x;
scanf("%d",&x); x++;
Access(&p[x]); Splay(&p[x]);
printf("%d\n",p[x].s);
}
else {
int x,y;
scanf("%d%d",&x,&y); x++;
if(x+y<=n) Link(&p[x],&p[x+y]);
else Link(&p[x],null);
}
}
return 0;
}