题目大意:给出n个点,定义一条边的负载就是它所在的当前能够联通的树上路过它的简单路径的数量,要求支持两个操作:加边,询问边的负载。保证加边不会出现环。
暴力用LCT维护子树信息。
LCT维护子树信息(子树信息LCT) LCT维护边权(边权LCT) 知识点讲解
与普通LCT的区别主要在于maintain函数(更新节点信息)和update函数(虚实边转换时更新信息,普通LCT没有)
siz表示正常Splay的size(然而在这道题里并没有什么卵用)
rsiz(real_size)表示LCT子树的size和(rsiz=ch[0]->rsiz+ch[1]->rsiz+xsiz+1,注意可能会包括父亲的rsiz)
xsiz(虚_size)表示与当前点连虚边的儿子的LCT子树size和(用于更新rsiz)
#include <cstdio>
#include <algorithm>
#define N 100005
using namespace std;
typedef long long LL;
struct Node {
Node *ch[2],*pa;
int dir() { return pa->ch[0]==this ? 0 : pa->ch[1]==this ? 1 : -1; }
int siz,xsiz,rsiz;
bool rev_mark;
Node();
void rev();
void pushdown();
void maintain();
void update(Node*,int);
}*null=new Node(),p[N];
Node :: Node():rev_mark(false),xsiz(0) {
pa=ch[0]=ch[1]=null;
siz=null?1:0;
rsiz=siz;
}
void Node :: rev() {
rev_mark=!rev_mark;
swap(ch[0],ch[1]);
return ;
}
void Node :: pushdown() {
if(rev_mark) {
ch[0]->rev();
ch[1]->rev();
rev_mark=false;
}
return ;
}
void Node :: maintain() {
siz=ch[0]->siz+ch[1]->siz+1;
rsiz=ch[0]->rsiz+ch[1]->rsiz+1+xsiz;
return ;
}
void Node :: update(Node* o,int k) {
xsiz+=k*o->rsiz;
rsiz+=k*o->rsiz;
return ;
}
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;
return ;
}
void To_pushdown(Node* o) {
static Node* q[N];
int top=0;
while(~(o->dir())) q[++top]=o, o=o->pa;
q[++top]=o;
while(top) q[top--]->pushdown();
return ;
}
void Splay(Node* o) {
To_pushdown(o);
int d;
while(~(d=o->dir())) {
if(o->pa->dir()==d) Rotate(o->pa->pa,d^1);
Rotate(o->pa,d^1);
}
return ;
}
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->pa;
}
return ;
}
void Move_to_root(Node* o) {
Access(o), Splay(o);
o->rev();
return ;
}
void Link(Node* x,Node* y) {
Move_to_root(x);
Move_to_root(y);
x->pa=y;
y->update(x,1);
return ;
}
LL query(Node* x,Node* y) {
Move_to_root(x);
Access(y), Splay(x);
return (LL)(x->xsiz+1)*(y->rsiz-x->xsiz-1);
}
int n,T;
int main() {
scanf("%d",&n);
for(scanf("%d",&T);T;T--) {
char mode[3];
int x,y;
scanf("%s%d%d",mode,&x,&y);
if(mode[0]=='A') Link(p+x,p+y);
else printf("%lld\n",query(p+x,p+y));
}
return 0;
}