Description
小强要在N个孤立的星球上建立起一套通信系统。这套通信系统就是连接N个点的一个树。
这个树的边是一条一条添加上去的。在某个时刻,一条边的负载就是它所在的当前能够
联通的树上路过它的简单路径的数量。
例如,在上图中,现在一共有了5条边。其中,(3,8)这条边的负载是6,因
为有六条简单路径2-3-8,2-3-8-7,3-8,3-8-7,4-3-8,4-3-8-7路过了(3,8)。
现在,你的任务就是随着边的添加,动态的回答小强对于某些边的负载的
询问。
Input
第一行包含两个整数N,Q,表示星球的数量和操作的数量。星球从1开始编号。
接下来的Q行,每行是如下两种格式之一:
A x y 表示在x和y之间连一条边。保证之前x和y是不联通的。
Q x y 表示询问(x,y)这条边上的负载。保证x和y之间有一条边。
1≤N,Q≤100000
Output
对每个查询操作,输出被查询的边的负载。
树链剖分预处理所有操作完成后的森林,树状数组维护区间和,按顺序处理询问和修改,用并查集维护连通性和当前每棵树的根
对询问a,b,若fa[b]=a则ans= b的子树大小*(a,b所在树的大小-b的子树大小)
复杂度O(qlog2n)
#include<cstdio> inline int read(){ int x=0,c=getchar(); while(c>57||c<48)c=getchar(); while(c>47&&c<58)x=x*10+c-48,c=getchar(); return x; } inline char readchr(){ int c=getchar(); while(c!='A'&&c!='Q')c=getchar(); return c; } const int N=100005; int n,q,M; int f[N],bit[N]; int qo[N],q1[N],q2[N]; int es[N*2],enx[N*2],e0[N],ep=2; int dep[N],sz[N],fa[N],son[N],top[N],id[N],idp=1; inline void inc(int x,int y){ while(x<M)bit[x]+=y,x+=x&-x; } inline int sum(int x){ int s=0; while(x)s+=bit[x],x-=x&-x; return s+1; } inline void addedge(int x,int y){ es[ep]=y;enx[ep]=e0[x];e0[x]=ep++; es[ep]=x;enx[ep]=e0[y];e0[y]=ep++; } void f1(int w,int pa){ fa[w]=pa; sz[w]=1; for(int i=e0[w];i;i=enx[i]){ int u=es[i]; if(u==pa)continue; dep[u]=dep[w]+1; f1(u,w); sz[w]+=sz[u]; if(sz[u]>sz[son[w]])son[w]=u; } } void f2(int w,int tp){ id[w]=idp++; top[w]=tp; if(son[w])f2(son[w],tp); for(int i=e0[w];i;i=enx[i]){ int u=es[i]; if(u!=fa[w]&&u!=son[w])f2(u,u); } } inline void modify(int x,int y,int v){ int a=top[x],b=top[y]; while(a!=b){ inc(id[x]+1,-v); inc(id[a],v); x=fa[a];a=top[x]; } inc(id[x]+1,-v); inc(id[y],v); } inline int get(int x){ int a=x,c; while(x!=f[x])x=f[x]; while(x!=(c=f[a]))f[a]=x,a=c; return x; } int main(){ n=read();q=read(); M=n+2; for(int i=0;i<q;i++){ qo[i]=readchr(); q1[i]=read();q2[i]=read(); if(qo[i]=='A')addedge(q1[i],q2[i]); } for(int i=1;i<=n;i++)f[i]=i; for(int i=1;i<=n;i++)if(!id[i]){ f1(i,0); f2(i,i); } for(int i=0;i<q;i++){ int o=qo[i],a=q1[i],b=q2[i]; if(o=='A'){ int c=get(a),d=get(b); if(dep[c]<dep[d]){ modify(a,c,sum(id[b])); f[d]=c; }else{ modify(b,d,sum(id[a])); f[c]=d; } }else{ if(dep[a]<dep[b]){ int s=sum(id[b]); printf("%lld ",s*1ll*(sum(id[get(a)])-s)); }else{ int s=sum(id[a]); printf("%lld ",s*1ll*(sum(id[get(b)])-s)); } } } return 0; }
理论上lct复杂度更小...