zoukankan      html  css  js  c++  java
  • HDU5511 : Minimum Cut-Cut

    设$d[x]$表示端点位于$x$子树内部的非树边条数,那么有两种情况:

    $1.$割去的两条树边$(x,fa[x]),(y,fa[y])$中,$x$是$y$的祖先,那么此时需要割去的非树边数量为$d[x]-d[y]$。

    显然固定$x$之后$y$越靠上越好,因此$y$一定是$x$的儿子,枚举即可,时间复杂度$O(n)$。

    $2.$一般化的情况,此时$x eq y$,需要割去的非树边数量为$d[x]+d[y]-2cnt(x,y)$,其中$cnt(x,y)$表示一端在$x$子树中,另一端在$y$子树中的非树边数量。

    枚举$x$,对于每个$y$维护$d[y]-2cnt(x,y)$。

    首先需要把$x$子树的$cnt$合并,然后对于一条端点恰好为$x$的非树边$(x,u)$,需要把$u$到根路径上的$d-2cnt$都减去$2$。

    树链剖分+线段树维护即可,时间复杂度$O(mlog^2n)$。

    直接实现的话,空间复杂度也为$O(mlog^2n)$,不能承受。

    每次先dfs重儿子,将$x$的重儿子的线段树直接作为$x$的线段树,然后依次与轻儿子合并,同时将废弃线段树节点回收利用。

    如此一来,只有经过轻边时,才会多开一棵动态开点的线段树,那么一共只会同时存在$O(log n)$棵线段树。

    每棵线段树就算开满也只有$O(n)$的空间,因此空间复杂度为$O(nlog n)$。

    #include<cstdio>
    const int N=20010,M=100010,E=1200000;
    int Case,cas,n,m,i,x,y,g[N],v[N<<1],nxt[N<<1],ed,ans;
    int d[N],G[N],V[M<<1],NXT[M<<1],ED;
    int f[N],size[N],son[N],top[N],loc[N],dfn,q[N];
    int T[N],l[E],r[E],tag[E],val[E],pool[E],cur,w[66000];
    inline void add(int x,int y){v[++ed]=y;nxt[ed]=g[x];g[x]=ed;}
    inline void ADD(int x,int y){d[x]++;V[++ED]=y;NXT[ED]=G[x];G[x]=ED;}
    inline void umin(int&a,int b){a>b?(a=b):0;}
    inline int min(int a,int b){return a<b?a:b;}
    void dfs(int x){
      size[x]=1;
      for(int i=g[x];i;i=nxt[i])if(v[i]!=f[x]){
        f[v[i]]=x;
        dfs(v[i]);
        size[x]+=size[v[i]],d[x]+=d[v[i]];
        if(size[v[i]]>size[son[x]])son[x]=v[i];
      }
      if(x>1)for(int i=g[x];i;i=nxt[i])if(v[i]!=f[x])umin(ans,d[x]-d[v[i]]);
    }
    void dfs2(int x,int y){
      loc[x]=++dfn;top[x]=y;
      if(son[x])dfs2(son[x],y);
      for(int i=g[x];i;i=nxt[i])if(v[i]!=son[x]&&v[i]!=f[x])dfs2(v[i],v[i]);
    }
    void build(int x,int a,int b){
      if(a==b){w[x]=q[a];return;}
      int mid=(a+b)>>1;
      build(x<<1,a,mid),build(x<<1|1,mid+1,b);
      w[x]=min(w[x<<1],w[x<<1|1]);
    }
    inline int newnode(int o){
      int x=pool[cur--];
      l[x]=r[x]=tag[x]=0;val[x]=w[o];
      return x;
    }
    inline void tag1(int x,int p){tag[x]+=p;val[x]+=p;}
    inline void pb(int x,int o){
      if(tag[x]){
        if(!l[x])l[x]=newnode(o<<1);
        if(!r[x])r[x]=newnode(o<<1|1);
        tag1(l[x],tag[x]),tag1(r[x],tag[x]),tag[x]=0;
      }
    }
    inline void up(int x,int o){
      if(!l[x])l[x]=newnode(o<<1);
      if(!r[x])r[x]=newnode(o<<1|1);
      val[x]=min(val[l[x]],val[r[x]]);
    }
    void change(int&x,int o,int a,int b,int c,int d,int p){
      if(!x)x=newnode(o);
      if(c<=a&&b<=d){tag1(x,p);return;}
      pb(x,o);
      int mid=(a+b)>>1;
      if(c<=mid)change(l[x],o<<1,a,mid,c,d,p);
      if(d>mid)change(r[x],o<<1|1,mid+1,b,c,d,p);
      up(x,o);
    }
    inline void chain(int&T,int x){
      while(top[x]!=1)change(T,1,1,n,loc[top[x]],loc[x],-2),x=f[top[x]];
      if(x>1)change(T,1,1,n,2,loc[x],-2);
    }
    int merge(int x,int y,int o,int a,int b){
      if(!x||!y)return x+y;
      if(a==b)tag[x]+=tag[y];
      else{
        pb(x,o),pb(y,o);
        int mid=(a+b)>>1;
        l[x]=merge(l[x],l[y],o<<1,a,mid);
        r[x]=merge(r[x],r[y],o<<1|1,mid+1,b);
        up(x,o);
      }
      pool[++cur]=y;
      return x;
    }
    void clear(int x,int a,int b){
      if(!x)return;
      pool[++cur]=x;
      if(a==b)return;
      int mid=(a+b)>>1;
      clear(l[x],a,mid),clear(r[x],mid+1,b);
    }
    void dfs3(int x){
      if(son[x])dfs3(son[x]),T[x]=T[son[x]];
      for(int i=g[x];i;i=nxt[i])if(v[i]!=son[x]&&v[i]!=f[x])dfs3(v[i]),T[x]=merge(T[x],T[v[i]],1,1,n);
      if(x==1)return;
      for(int i=G[x];i;i=NXT[i])chain(T[x],V[i]);
      change(T[x],1,1,n,loc[x],loc[x],M);
      umin(ans,d[x]+val[T[x]]);
      change(T[x],1,1,n,loc[x],loc[x],-M);
    }
    int main(){
      for(i=1;i<E;i++)pool[++cur]=i;
      scanf("%d",&Case);
      for(cas=1;cas<=Case;cas++){
        scanf("%d%d",&n,&m);ans=M;
        for(i=1;i<n;i++)scanf("%d%d",&x,&y),add(x,y),add(y,x);
        for(;i<=m;i++)scanf("%d%d",&x,&y),ADD(x,y),ADD(y,x);
        dfs(1),dfs2(1,1);
        for(i=1;i<=n;i++)q[loc[i]]=d[i];
        build(1,1,n);
        dfs3(1);
        printf("Case #%d: %d
    ",cas,ans+2);
        clear(T[1],1,n);
        for(ed=ED=dfn=0,i=1;i<=n;i++)g[i]=d[i]=G[i]=f[i]=size[i]=son[i]=T[i]=0;
      }
      return 0;
    }
    

      

  • 相关阅读:
    python3.4下django集成使用xadmin后台
    在django中集成ckeditor富文本
    python多线程爬虫设计及实现示例
    利用python将mysql中的数据导入excel
    win7中python3.4下安装scrapy爬虫框架(亲测可用)
    windows下pycharm远程调试pyspark
    python连接impala(安装impyla)
    将百度坐标转换的javascript api官方示例改写成传统的回调函数形式
    csv导入数据到mysql
    windows下python连接oracle数据库
  • 原文地址:https://www.cnblogs.com/clrs97/p/7438256.html
Copyright © 2011-2022 走看看