• bzoj2888: 资源运输


    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
    ",ans);
            else mg(qs[i][0],qs[i][1]);
        }
        return 0;
    }
  • 相关阅读:
    sql注入式攻击的原理及实例分析 (转载)
    java中静态初始化块、初始化块和构造方法的理解 (转载)
    Java Web应用开发中的一些概念(转载)
    Map.Entry的使用(转载)
    java对象的存储位置(转载)-- 结合上一篇一起学习
    深入Java对象及元素的存储区域(转载)
    Java 面试题问与答:编译时与运行时(转载)看了一遍还不是很懂 先收着
    Liferay应用程序模板如何获取自定义结构的字段值
    FreeMarker 快速入门
    Tomcat9.x配置规范
  • 原文地址:https://www.cnblogs.com/ccz181078/p/6872618.html
Copyright © 2020-2023  润新知