ccz181078

  博客园 :: 首页 :: 博问 :: 闪存 :: 新随笔 :: 联系 :: :: 管理 ::

Description

       小Y盯上了最近发行的即时战略游戏——ResourceTransport。但在前往通关之路的道路上,一个小游戏挡住了小Y的步伐。“国家的本质是生产与收集资源”是整款游戏的核心理念,这个小游戏也不例外。简单的说,用户需要管理一个国家,使其繁荣富强。
       一个国家含有N个城市,游戏开始时城市间没有任何道路。城市可以通过高速公路连接。为了减少建设费用,每对城市间最多存在一条路径。
       小Y拥有极强的游戏天赋,很快就把所有城市的生产能力提到了满级,把高速公路的建设费用修改成了0。
悲剧的是,对于每个连通的城市群,都要把该城市群中的某个城市设立成资源集合处,小Y把这件事忘了;更悲剧的是,建造高速公路这件事,小Y也忘了。
可小Y是个完美主义者,他请来了你帮他设立资源集合处,自己负责建造高速公路。假设连通城市群中的某个城市i到该城市群的资源集合处最少需要经过Di条高速公路,那么总运输费用为Sigma(Di)你需要在每个连通城市群中设立一个资源集合处,使得总费用最小。小Y有时会向你询问此时最小的总费用
问题很简单,麻烦的是小Y会在你好不容易算出最小总费用时建造一条新的高速公路。由于每个连通的城市群只能有一个资源集合处,所以最小总费用又得重新计算,这可真是个苦差事……

Input

第一行两个整数N,M分别表示国家中的城市数与小Y的操作数。
接下来M行,每行可能为:
       1.A x y:表示在城市x和城市y间建造一条高速公路,保证此操作出现N-1次;
       2.Q:表示小Y询问此时的最小总费用。

Output

       对于每个Q操作,单独输出一行一个整数Ans,表示所求的答案。

有一个结论是对树上任意一条边,在删去边得到的两棵子树中各取一个重心,它们在原树上的路径上会经过原树的至少一个重心

树链剖分+zkw线段树维护每个以重心为根的树上每个点的子树大小、子树中点的深度和,加边时启发式合并,重构较小的一棵树,考虑一步一步移动原有重心到新的重心,由于移动步数不超过较小的一棵树的大小,可以保证时间复杂度为$O(nlog^2n)$

#include<cstdio>
#include<cstring>
#include<algorithm>
const int N=40007;
int __;
char buf[N*30],*ptr=buf;
int _(){
    int x=0;
    while(*ptr<48)++ptr;
    while(*ptr>47)x=x*10+*ptr++-48;
    return x;
}
int _o(){
    while(*ptr<33)++ptr;
    return *ptr++;
}
int es[N*2],enx[N*2],e0[N],ep=2;
int n,m,qs[N*2][2];
int dep[N],fa[N],sz[N],son[N],top[N],id[N],idp=0;
void ae(int a,int b){
    es[ep]=b;enx[ep]=e0[a];e0[a]=ep++;
    es[ep]=a;enx[ep]=e0[b];e0[b]=ep++;
}
void f1(int w,int pa){
    dep[w]=dep[fa[w]=pa]+1;
    sz[w]=1;
    for(int i=e0[w];i;i=enx[i]){
        int u=es[i];
        if(u!=pa){
            f1(u,w);
            sz[w]+=sz[u];
            if(sz[u]>sz[son[w]])son[w]=u;
        }
    }
}
void f2(int w,int tp){
    top[w]=tp;
    id[w]=++idp;
    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);
    }
}
int lca(int x,int y){
    int a=top[x],b=top[y];
    while(a!=b){
        if(dep[a]>dep[b])x=fa[a],a=top[x];
        else y=fa[b],b=top[y];
    }
    return dep[x]<dep[y]?x:y;
}
int up(int x,int y){
    int a=top[x],b=top[y];
    while(a!=b){
        y=fa[b];
        if(x==y)return b;
        b=top[y];
    }
    return son[x];
}
int f[N],rt[N],siz[N],res[N],ans=0;
int gf(int x){
    while(x!=f[x])x=f[x]=f[f[x]];
    return x;
}
int tr[133333][3],mx;
#define A tr][0
#define B tr][1
#define C tr][2
int cnt=0;
void getv(int x,int&v1,int&v2){
    v1=v2=0;
    for(int w=x+mx;w;w>>=1){
        v1+=w[A];
        v2+=w[B]+w[C]*x;
    }
}
void setv(int x,int v1,int v2){
    int a1,a2,w=mx+x;
    getv(x,a1,a2);
    w[A]+=v1-a1;
    w[B]+=v2-a2;
}
void adds(int l,int r,int a,int b,int c){
    for(l+=mx-1,r+=mx+1;r-l!=1;l>>=1,r>>=1){
        if(~l&1){
            int w=l^1;
            w[A]+=a;
            w[B]+=b;
            w[C]+=c;
        }
        if(r&1){
            int w=r^1;
            w[A]+=a;
            w[B]+=b;
            w[C]+=c;
        }
    }
}
void add(int x,int y,int v1,int v2){
    int D1=dep[x]+dep[y]+1-dep[lca(x,y)]*2,D2=1;
    int a=top[x],b=top[y];
    while(a!=b){
        if(dep[a]>dep[b]){
            adds(id[a],id[x],v1,v2+(D2+id[x])*v1,-v1);
            D2+=id[x]-id[a]+1;
            x=fa[a];a=top[x];
        }else{
            adds(id[b],id[y],v1,v2+(D1-id[y])*v1,v1);
            D1-=id[y]-id[b]+1;
            y=fa[b];b=top[y];
        }
    }
    if(dep[x]>dep[y]){
        adds(id[y],id[x],v1,v2+(D2+id[x])*v1,-v1);
    }else{
        adds(id[x],id[y],v1,v2+(D1-id[y])*v1,v1);
    }
}
bool chk(int&w,int u){
    int w1,w2,u1,u2;
    getv(id[w],w1,w2);
    getv(id[u],u1,u2);
    if(w2>u2+(w1-u1)+(w2-u2-u1)){
        setv(id[w],w1-u1,w2-u2-u1);
        setv(id[u],w1,u2+(w1-u1)+(w2-u2-u1));
        w=u;
        return 1;
    }
    return 0;
}
int sz1[N],ds1[N];
void dfs(int w,int pa){
    sz1[w]=1;ds1[w]=0;
    for(int i=e0[w];i;i=enx[i]){
        int u=es[i];
        if(u!=pa){
            dfs(u,w);
            sz1[w]+=sz1[u];
            ds1[w]+=ds1[u]+sz1[u];
        }
    }
    setv(id[w],sz1[w],ds1[w]);
}
void mg(int x,int y){
    int a=gf(x),b=gf(y);
    if(siz[a]<siz[b])std::swap(a,b),std::swap(x,y);
    dfs(y,0);
    ae(x,y);
    add(x,rt[a],sz1[y],ds1[y]);
    f[b]=a;
    siz[a]+=siz[b];
    ans-=res[a]+res[b];
    int c=lca(rt[a],rt[b]),w=rt[a];
    while(w!=c)if(!chk(w,fa[w]))goto o1;
    while(w!=rt[b])if(!chk(w,up(w,rt[b])))break;
    o1:
    rt[a]=w;
    getv(id[w],__,res[a]);
    ans+=res[a];
}
int main(){
    fread(buf,1,sizeof(buf),stdin)[buf]=0;
    n=_();m=_();
    for(int i=1;i<=n;++i){
        f[i]=rt[i]=i;
        siz[i]=1;
    }
    for(int i=1;i<=m;++i){
        if(_o()=='A'){
            qs[i][0]=_();
            qs[i][1]=_();
            ae(qs[i][0],qs[i][1]);
        }else qs[i][0]=-1;
    }
    f1(1,0);f2(1,1);
    ep=2;
    memset(e0,0,n+2<<2);
    for(mx=1;mx<=idp+4;mx<<=1);
    for(int i=1;i<=idp;++i)(mx+i)[A]=1;
    for(int i=1;i<=m;++i){
        if(qs[i][0]==-1)printf("%d\n",ans);
        else mg(qs[i][0],qs[i][1]);
    }
    return 0;
}

 

posted on 2017-05-18 11:54  nul  阅读(258)  评论(0编辑  收藏  举报