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;
    }
    

      

  • 相关阅读:
    React在componentDidMount里面发送请求
    React 术语词汇表
    React里受控与非受控组件
    React和Vue等框架什么时候操作DOM
    【LeetCode】79. Word Search
    【LeetCode】91. Decode Ways
    【LeetCode】80. Remove Duplicates from Sorted Array II (2 solutions)
    【LeetCode】1. Two Sum
    【LeetCode】141. Linked List Cycle (2 solutions)
    【LeetCode】120. Triangle (3 solutions)
  • 原文地址:https://www.cnblogs.com/clrs97/p/7438256.html
Copyright © 2011-2022 走看看