传送门biu~
用LCT维护子树信息。
LCT维护子树信息(子树信息LCT) LCT维护边权(边权LCT) 知识点讲解
xsiz代表节点的虚儿子的size和。
rsiz代表该点在Splay中的size加上该点的xsiz。
每次maintain操作可以更新节点的rsiz值。
增加一个update函数来实现实儿子到虚儿子的转化(改变节点xsiz值),在Access和Link这两个改变边的虚实关系的函数中调用。
#include<bits/stdc++.h>
using namespace std;
struct Node{
Node *ch[2],*fa;
bool rev_mark;
int rsiz,xsiz;
Node();
inline int dir(){
if(fa->ch[0]==this) return 0;
if(fa->ch[1]==this) return 1;
return -1;
}
inline void rev(){rev_mark^=1;}
inline void update(Node *o,int d){xsiz+=d*o->rsiz;}
inline void pushdown(){
if(!rev_mark) return;
swap(ch[0],ch[1]);
ch[0]->rev();
ch[1]->rev();
rev_mark=false;
}
inline void maintain(){rsiz=ch[0]->rsiz+ch[1]->rsiz+xsiz+1;}
}*null=new Node,p[100005];
Node :: Node(){
ch[0]=ch[1]=fa=null;
rev_mark=false;
rsiz=1;
xsiz=0;
}
void To_pushdown(Node *o){
if(~o->dir()) To_pushdown(o->fa);
o->pushdown();
}
inline void Rotate(Node *o,int d){
Node *p=o->ch[d^1];
p->ch[d]->fa=o; o->ch[d^1]=p->ch[d];
p->ch[d]=o;
o->maintain(); p->maintain();
if(~o->dir()) o->fa->ch[o->dir()]=p;
p->fa=o->fa; o->fa=p;
}
inline void Splay(Node *o){
To_pushdown(o);
while(~o->dir()){
if(o->dir()==o->fa->dir()) Rotate(o->fa->fa,o->dir()^1);
Rotate(o->fa,o->dir()^1);
}
}
inline void Access(Node *o){
Node *p=null;
while(o!=null){
Splay(o);
o->update(o->ch[1],1); o->update(p,-1);
o->ch[1]=p; o->maintain();
p=o;
o=o->fa;
}
}
inline void Move_to_root(Node *o){
Access(o); Splay(o);
o->rev();
}
inline void Link(Node *x,Node *y){
Move_to_root(x);
Move_to_root(y);
x->fa=y; y->update(x,1);
}
inline long long Query(Node *x,Node *y){
Move_to_root(x);
Access(y); Splay(y);
return 1ll*x->rsiz*(y->xsiz+1);
}
int main(){
null->rsiz=0;
int n,T;
scanf("%d%d",&n,&T);
while(T--){
char opt[2];int x,y;
scanf("%s%d%d",opt,&x,&y);
if(opt[0]=='A') Link(&p[x],&p[y]);
else printf("%lld\n",Query(&p[x],&p[y]));
}
return 0;
}