题意:
N<=1e5个点,Q<=1e5个操作。
支持加一条边(u,v)(保证图是森林)、询问经过边(u,v)的简单路径条数(保证(u,v)存在)。
分析:
数据结构学傻了的我,表示并不会用树链剖分做这个题……
首先,这道题的询问,可以看成是假设断掉某条边后,两端点的子树size相乘。(一个简单的乘法原理???)
但是LCT模板里并没有这样的操作,那怎么办?难不成发明一个?
(有dalao还就真的发明了一个……)
我们的LCT中的边分为实边和虚边,假如在一棵splay树(实边)中,我们自然可以轻而易举的求出一个点的子树size——只要维护一个size数组就好了嘛。
但是现在存在虚边,所以解决虚边问题是当务之急,那么我们就需要多维护一个数组,设siz[x]表示对于点x,经由虚边连接的子树的大小,那么在LCT的pushup操作中,我们就把一个点总的size(记为sz[x]数组)赋为两个实儿子的sz,加上虚子树的数量,加上他自己即可。(sz[x]=sz[lson]+sz[rson]+siz[x]+1)
那么我们维护这个子树总size有什么用呢?
考虑到在LCT中,实边和虚边是会互相转化的,即在link的过程中会增加虚边,在access过程中虚实边会相互转化,所以我们在相应位置就使用相应的策略,将两类size数组维护好即可,最终询问时,我们split(x,y),使实边存在于两点之间,这样我们只需要计算两个虚子树size相乘的结果即可!
(祭天:我把#define rc(x) t[x][1]写成了#define rc(X) t[x][1],于是能过样例,但是Wa了一宿……)
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
![](https://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif)
1 #include<bits/stdc++.h> 2 #define ll long long 3 #define lc(x) t[x][0] 4 #define rc(x) t[x][1] 5 using namespace std; 6 const int N=100005; 7 struct LCT{ 8 int t[N][2],siz[N],rev[N],sz[N],s[N],tp,fa[N]; 9 void pushup(int x){ 10 sz[x]=sz[lc(x)]+sz[rc(x)]+siz[x]+1; 11 } void revers(int x){ 12 rev[x]^=1;swap(lc(x),rc(x)); 13 } void pushdown(int x){ 14 if(rev[x]){ rev[x]=0; 15 if(lc(x)) revers(lc(x)); 16 if(rc(x)) revers(rc(x)); 17 } return ; 18 } bool pdrt(int x){ 19 return rc(fa[x])!=x&&lc(fa[x])!=x; 20 } void rotate(int x){ 21 int y=fa[x];int z=fa[y]; 22 int dy=(rc(y)==x),dz=(rc(z)==y); 23 if(!pdrt(y)) t[z][dz]=x; 24 t[y][dy]=t[x][dy^1];fa[t[y][dy]]=y; 25 t[x][dy^1]=y;fa[y]=x;fa[x]=z; 26 pushup(y); 27 } void splay(int x){ 28 s[++tp]=x; 29 for(int i=x;!pdrt(i);i=fa[i]) 30 s[++tp]=fa[i]; 31 while(tp) pushdown(s[tp--]); 32 while(!pdrt(x)){ 33 int y=fa[x];int z=fa[y]; 34 if(!pdrt(y)) 35 if(rc(y)==x^rc(z)==y) rotate(x); 36 else rotate(y);rotate(x); 37 } pushup(x);return ; 38 } void access(int x){ 39 for(int i=0;x;x=fa[i=x]) 40 {splay(x);siz[x]+=sz[rc(x)]; 41 siz[x]-=sz[rc(x)=i];} 42 } void mkrt(int x){ 43 access(x);splay(x);revers(x); 44 } int fdrt(int x){ 45 access(x);splay(x); 46 while(lc(x)) pushdown(x),x=lc(x); 47 return x; 48 } void split(int x,int y){ 49 mkrt(x);access(y);splay(y); 50 } void link(int x,int y){ 51 mkrt(x);if(fdrt(y)!=x) 52 fa[x]=y,siz[y]+=sz[x],pushup(y); 53 } 54 }lct;int n,m,q; 55 int main(){ 56 scanf("%d%d",&n,&q);char c[10]; 57 for(int i=1;i<=n;i++) lct.sz[i]=1; 58 while(q--){ int x,y; 59 scanf("%s%d%d",c,&x,&y); 60 if(c[0]=='A') lct.link(x,y); 61 else lct.split(x,y), 62 printf("%lld\n",(ll) 63 (lct.siz[x]+1)*(lct.siz[y]+1)); 64 } return 0; 65 }