bzoj4530 [Bjoi2014]大融合

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复杂度更小...

原文地址:https://www.cnblogs.com/ccz181078/p/5396596.html