LOJ#2230. 「BJOI2014」大融合
题目描述
小强要在$N$个孤立的星球上建立起一套通信系统。这套通信系统就是连接$N$个点的一个树。这个树的边是一条一条添加上去的。
在某个时刻,一条边的负载就是它所在的当前能够联通的树上路过它的简单路径的数量。
例如,在上图中,现在一共有五条边。其中,$(3,8)$这条边的负载是$6$,因为有六条简单路径$2-3-8,\ 2-3-8-7,\ 3-8,\ 3-8-7,\ 4-3-8,\ 4-3-8-7$路过了$(3,8)$。
现在,你的任务就是随着边的添加,动态的回答小强对于某些边的负载的询问。
输入格式
第一行包含两个整数$N,Q$,表示星球的数量和操作的数量。星球从$1$开始编号。
接下来的$Q$行,每行是如下两种格式之一:
A x y
表示在$x$和$y$之间连一条边。保证之前$x$和$y$是不联通的。Q x y
表示询问$(x,y)$这条边上的负载。保证$x$和$y$之间有一条边。
输出格式
对每个查询操作,输出被查询的边的负载。
样例
样例输入
8 6
A 2 3
A 3 4
A 3 8
A 8 7
A 6 5
Q 3 8
样例输出
6
数据范围与提示
对于所有数据,$1 \leq N,Q \leq 100000$。
题解Here!
$LCT$大法好!
维护虚树中每个节点的虚子节点个数。
连边时注意:不是$makeroot$,是$split$。(坑了我好久。。。)
还有$access$时维护一下即可。
最后答案就是:
$$\text{x的虚子节点个数}\times(\text{y的虚子节点个数}-\text{x的虚子节点个数})$$
附代码:
#include<iostream> #include<algorithm> #include<cstdio> #define MAXN 100010 using namespace std; int n,m; struct node{ int f,v,s,flag,son[2]; }a[MAXN]; inline int read(){ int date=0,w=1;char c=0; while(c<'0'||c>'9'){if(c=='-')w=-1;c=getchar();} while(c>='0'&&c<='9'){date=date*10+c-'0';c=getchar();} return date*w; } inline bool isroot(int rt){ return a[a[rt].f].son[0]!=rt&&a[a[rt].f].son[1]!=rt; } inline void pushup(int rt){ if(!rt)return; a[rt].s=a[a[rt].son[0]].s+a[a[rt].son[1]].s+a[rt].v+1; } inline void pushdown(int rt){ if(!rt||!a[rt].flag)return; a[a[rt].son[0]].flag^=1;a[a[rt].son[1]].flag^=1;a[rt].flag^=1; swap(a[rt].son[0],a[rt].son[1]); } inline void turn(int rt){ int x=a[rt].f,y=a[x].f,k=a[x].son[0]==rt?1:0; if(!isroot(x)){ if(a[y].son[0]==x)a[y].son[0]=rt; else a[y].son[1]=rt; } a[rt].f=y;a[x].f=rt;a[a[rt].son[k]].f=x; a[x].son[k^1]=a[rt].son[k];a[rt].son[k]=x; pushup(x);pushup(rt); } void splay(int rt){ int top=0,stack[MAXN]; stack[++top]=rt; for(int i=rt;!isroot(i);i=a[i].f)stack[++top]=a[i].f; while(top)pushdown(stack[top--]); while(!isroot(rt)){ int x=a[rt].f,y=a[x].f; if(!isroot(x)){ if((a[y].son[0]==x)^(a[x].son[0]==rt))turn(rt); else turn(x); } turn(rt); } } void access(int rt){ for(int i=0;rt;i=rt,rt=a[rt].f){ splay(rt); a[rt].v+=a[a[rt].son[1]].s-a[i].s; a[rt].son[1]=i; pushup(rt); } } inline void makeroot(int rt){access(rt);splay(rt);a[rt].flag^=1;} inline void split(int x,int y){makeroot(x);access(y);splay(y);} inline void link(int x,int y){ split(x,y); a[x].f=y; a[y].v+=a[x].s; pushup(y); } void work(){ char ch[2]; int x,y; n=read();m=read(); for(int i=1;i<=n;i++)a[i].s=1; while(m--){ scanf("%s",ch);x=read();y=read(); if(ch[0]=='A')link(x,y); if(ch[0]=='Q'){ split(x,y); printf("%lld\n",(long long)a[x].s*(a[y].s-a[x].s)); } } } int main(){ work(); return 0; }