传送门
线段树合并菜题。
题意简述: n n n个点,支持连边以及查询一个点所在连通块中经过这个点的路径条数,保证这张图时刻为森林。
思路:
先建出所有操作完之后的树统计出 d f s dfs dfs序 注意有可能是森林而不是树
然后用线段树合并维护每棵子树的 s i z e size size即可。
为了方便,我们将每个节点的 i n in in作为下标插入线段树中,这样可以方便的统计出一棵子树在 [ i n v , o u t v ] , v ∈ s u b t r e e [in_v,out_v],v\in subtree [inv,outv],v∈subtree中的 s i z e size size,然后对于查询的边 ( u , v ) (u,v) (u,v)(假设 u u u是父亲, r t rt rt是这棵子树根节点),那么 a n s = ( s i z e r t − s i z e v ) ∗ s i z e v ans=(size_{rt}-size_v)*size_v ans=(sizert−sizev)∗sizev,然后就可以转化为区间查询了。
代码:
#include
#define ri register int
using namespace std;
inline int read(){
int ans=0;
char ch=getchar();
while(!isdigit(ch))ch=getchar();
while(isdigit(ch))ans=(ans<<3)+(ans<<1)+(ch^48),ch=getchar();
return ans;
}
const int N=1e5+5;
int n,q,in[N],out[N],rt[N],tot=0,cnt=0,son[N*20][2],siz[N*20],dep[N],anc[N];
vector<int>e[N];
struct Qur{int x,y,k;}qry[N];
inline void build(int&p,int l,int r,int k){
siz[p=++cnt]=1,son[p][0]=son[p][1]=0;
if(l==r)return;
int mid=l+r>>1;
k<=mid?build(son[p][0],l,mid,k):build(son[p][1],mid+1,r,k);
}
inline int merge(int x,int y,int l,int r){
if(!x||!y)return x+y;
siz[x]+=siz[y];
if(l==r)return x;
int mid=l+r>>1;
son[x][0]=merge(son[x][0],son[y][0],l,mid);
son[x][1]=merge(son[x][1],son[y][1],mid+1,r);
return x;
}
inline int query(int p,int l,int r,int ql,int qr){
if(!p||ql>r||qr<l)return 0;
if(ql<=l&&r<=qr)return siz[p];
int mid=l+r>>1;
if(qr<=mid)return query(son[p][0],l,mid,ql,qr);
if(ql>mid)return query(son[p][1],mid+1,r,ql,qr);
return query(son[p][0],l,mid,ql,mid)+query(son[p][1],mid+1,r,mid+1,qr);
}
void dfs(int p,int fa){
in[p]=++tot;
for(ri i=0,v;i<e[p].size();++i)if((v=e[p][i])^fa)dep[v]=dep[p]+1,dfs(v,p);
out[p]=tot;
}
inline int find(int x){return x==anc[x]?x:anc[x]=find(anc[x]);}
int main(){
n=read(),q=read();
for(ri i=1;i<=q;++i){
char op[2];
scanf("%s",op),qry[i].x=read(),qry[i].y=read(),qry[i].k=op[0]!='A';
if(!qry[i].k)e[qry[i].x].push_back(qry[i].y),e[qry[i].y].push_back(qry[i].x);
}
for(ri i=1;i<=n;++i){
if(!in[i])dfs(i,0);
build(rt[i],1,n,in[i]),anc[i]=i;
}
for(ri i=1,u,v;i<=q;++i){
u=qry[i].x,v=qry[i].y;
if(dep[u]>dep[v])swap(u,v);
if(!qry[i].k)rt[find(u)]=merge(rt[find(u)],rt[find(v)],1,n),anc[find(v)]=anc[(u)];
else{
int x=find(v),y=query(rt[x],1,n,in[v],out[v]);
cout<<(long long)y*(siz[rt[x]]-y)<<'\n';
}
}
return 0;
}