• BZOJ2888 : 资源运输


    显然资源集合处就是树的重心,这题需要动态维护树的重心。

    每个连通块以重心为根,用link-cut tree维护每个点的子树大小以及子树内所有点到它的距离和。

    合并两个连通块时,考虑启发式合并,暴力往大的树中添加叶子。

    添加叶子时,需要将叶子到重心路径上所有点的子树大小+1,距离和则加上一个等差数列。

    并且新的重心是可能是原来的重心或者原来重心到叶子路径上的第一个点,暴力即可。

    时间复杂度$O(nlog^2n)$。

     

    #include<cstdio>
    #define N 40010
    int n,m,i,x,y,ans;char op[5];
    int g[N],v[N<<1],nxt[N<<1],ed,f[N],son[N][2],val[N],tag[N],sum[N],ts[N],td[N],size[N],tmp[N];
    inline void swap(int&a,int&b){int c=a;a=b;b=c;}
    inline bool isroot(int x){return !f[x]||son[f[x]][0]!=x&&son[f[x]][1]!=x;}
    inline void add1(int x,int p){if(!x)return;val[x]+=p;tag[x]+=p;}
    inline void add2(int x,int s,int d){if(!x)return;sum[x]+=s+size[son[x][1]]*d;ts[x]+=s;td[x]+=d;}
    inline void pb(int x){
      if(tag[x]){
        add1(son[x][0],tag[x]);
        add1(son[x][1],tag[x]);
        tag[x]=0;
      }
      if(td[x]){
        add2(son[x][0],ts[x]+(size[son[x][1]]+1)*td[x],td[x]);
        add2(son[x][1],ts[x],td[x]);
        ts[x]=td[x]=0;
      }
    }
    inline void up(int x){size[x]=size[son[x][0]]+size[son[x][1]]+1;}
    inline void rotate(int x){
      int y=f[x],w=son[y][1]==x;
      son[y][w]=son[x][w^1];
      if(son[x][w^1])f[son[x][w^1]]=y;
      if(f[y]){
        int z=f[y];
        if(son[z][0]==y)son[z][0]=x;else if(son[z][1]==y)son[z][1]=x;
      }
      f[x]=f[y];f[y]=x;son[x][w^1]=y;up(y);
    }
    inline void splay(int x){
      int s=1,i=x,y;tmp[1]=i;
      while(!isroot(i))tmp[++s]=i=f[i];
      while(s)pb(tmp[s--]);
      while(!isroot(x)){
        y=f[x];
        if(!isroot(y)){if((son[f[y]][0]==y)^(son[y][0]==x))rotate(x);else rotate(y);}
        rotate(x);
      }
      up(x);
    }
    inline void access(int x){for(int y=0;x;y=x,x=f[x])splay(x),son[x][1]=y,up(x);}
    inline int root(int x){access(x);splay(x);while(son[x][0])x=son[x][0];return x;}
    inline void addleaf(int x,int y){
      f[y]=x,son[y][0]=son[y][1]=val[y]=tag[y]=sum[y]=ts[y]=td[y]=0,size[y]=1;
      x=root(x),access(y),splay(x),add1(x,1),add2(x,0,1);
      for(y=son[x][1];son[y][0];y=son[y][0]);splay(y);
      int vx=val[x],vy=val[y];
      if(vy*2>vx){
        val[y]=vx,val[x]-=vy;
        sum[x]-=sum[y]+vy,sum[y]+=sum[x]+vx-vy;
        access(y),splay(x),son[x][0]=y,son[x][1]=0;
      }
    }
    void dfs(int x,int y){
      addleaf(y,x);
      for(int i=g[x];i;i=nxt[i])if(v[i]!=y)dfs(v[i],x);
    }
    inline void addedge(int x,int y){v[++ed]=y;nxt[ed]=g[x];g[x]=ed;}
    inline void link(int x,int y){
      int X=root(x),Y=root(y);
      ans-=sum[X]+sum[Y];
      if(val[X]<val[Y])swap(x,y);
      dfs(y,x),addedge(x,y),addedge(y,x);
      ans+=sum[root(x)];
    }
    int main(){
      scanf("%d%d",&n,&m);
      for(i=1;i<=n;i++)val[i]=size[i]=1;
      while(m--){
        scanf("%s",op);
        if(op[0]=='A')scanf("%d%d",&x,&y),link(x,y);
        if(op[0]=='Q')printf("%d
    ",ans);
      }
      return 0;
    }
    

      

  • 相关阅读:
    SpringBoot2.1.6 整合CXF 实现Webservice
    一次线上CPU高的问题排查实践
    SpringBoot整合升级Spring Security 报错 【The request was rejected because the URL was not normalized】
    Web服务器☞Apache VS Nginx
    PHP 遍历一个文件夹下所有文件和子文件夹的方法
    PHP 使用 header 方式实现文件下载功能
    PHP gd 库添加 freetype
    MySQL varchar 最大长度,text 类型占用空间剖析
    S.O.L.I.D: PHP 面向对象设计的五个基准原则
    PHP不重新编译,单独添加模块扩展的方法
  • 原文地址:https://www.cnblogs.com/clrs97/p/4776809.html
Copyright © 2020-2023  润新知