hdu5452

转自

因为生成树中只有一条边属于割集,那么割对生成树来说只是分成了两个子树,那么就考虑割生成树上割哪条边是最优的。

首先对生成树进行建树剖,对于每条非树边的两个端点u和v,对 u –> v 在生成树上的简单路径上的边权值加一,最后找到所有边权值最小的边,就是属于最小割的边。
所有对找到的这条边的权值做贡献的边,一定是跨越了以这条边分开的两个子树,即如果要分开这两个子树,这些边也要割掉,这些边就是要求的最小割集。

这题卡常数,所以路径上边权加一的操作不能用线段树或者树状数组来更新,因为是操作完成后才对边权进行遍历,所以可以用差分前缀和来计算每条边被更新了几次。

import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.io.StreamTokenizer;
import java.math.BigInteger;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.NavigableSet;
import java.util.PriorityQueue;
import java.util.Queue;
import java.util.Scanner;
import java.util.Set;
import java.util.SortedSet;
import java.util.Stack;
import java.util.StringTokenizer;
import java.util.TreeSet;

public class Main {


    public static void main(String[] args) throws IOException{

           StreamTokenizer cin = new StreamTokenizer(new BufferedInputStream(System.in)); 
           InputReader in = new InputReader(System.in)  ;
           PrintWriter out = new PrintWriter(System.out) ;  
           int t = in.nextInt() ;
           for(int i = 1 ; i <= t ; i++){
                out.print("Case #" + i + ": ");
                new Task().solve(in, out) ;  
           }
           out.flush();
    }

}

class  Task{

       public void solve(InputReader in , PrintWriter out) throws IOException{


           int j , u , v  , k  , t , T = 1 , m , d  ;
           n = in.nextInt() ;
           m = in.nextInt()  ;
           init() ;
           for(int i = 1 ; i < n ; i++){
                       u = in.nextInt() ;
                       v = in.nextInt() ;
                       addedge(u , v) ;
           }

           dfs1(1 , 0 , 0) ;
           dfs2(1 , 1) ;

           for(int i = 1 ; i <= m - n + 1 ; i++){
                   u = in.nextInt() ;
                   v = in.nextInt() ;
                   if(tid[u] < tid[v]){
                           u ^= v ; v ^= u ; u ^= v ;
                   }
                   change2(u , v , 1) ;
           }

           gsum2() ;
           long res = ans2[2] ;
           for(int i = 2 ; i <= n ; i++) res = Math.min(res , ans2[i])  ;
           out.println(res+1) ;

       }

       static final  int  maxn = 20008 ;

       static long[] c1 = new long[maxn] ; 
       static long[] c2 = new long[maxn] ;
       static long[] ans1 = new long[maxn] ;
       static long[] ans2 = new long[maxn] ;
       int  n ;
       static int[] siz = new int[maxn] ;
       static int[] top = new int[maxn] ;
       static int[] son = new int[maxn] ;
       static int[] dep = new int[maxn] ;
       static int[] tid = new int[maxn] ;
       static int[] fa = new int[maxn] ;
       static int[] rank = new int[maxn] ;
       static int[] head = new int[maxn] ;
       static int[] to = new int[200008*2] ;
       static int[] next = new int[200008*2] ;

       int  edge ;
       int  tim ;

       void  init(){
             Arrays.fill(head, -1) ;
             Arrays.fill(son, -1) ;
             Arrays.fill(c2, 0) ;
             tim = edge = 0 ;
       }

       void  addedge(int u , int v){
             to[edge] = v ; next[edge] = head[u] ; head[u] = edge++ ;
             to[edge] = u ; next[edge] = head[v] ; head[v] = edge++ ;
       }

       void  dfs1(int u , int father , int d){
             dep[u] = d ;
             fa[u]  = father ;
             siz[u] = 1 ;
             for(int i = head[u] ; i != -1 ; i = next[i]){
                   int v = to[i] ;
                   if(v != father){
                        dfs1(v , u , d+1) ;
                        siz[u] += siz[v] ;
                        if(son[u] == -1 || siz[v] > siz[son[u]]) son[u] = v ;
                   }
             }
       }

       void  dfs2(int u , int tp){
             top[u] = tp ;
             tid[u] = ++tim ;
             rank[tid[u]] = u ;
             if(son[u] == -1) return  ;
             dfs2(son[u] , tp) ;
             for(int i = head[u] ; i != -1 ; i = next[i]){
                  int v = to[i] ;
                  if(v != son[u] && v != fa[u])  dfs2(v , v) ;
             }
       }

       void  in1(int l , int r , int c){
             c1[l] += c ;
             c1[r+1] -= c ;
       }

       void  gsum1(){
             long t = 0  ;
             for(int i = 1 ; i <= n ; i++){
                t += c1[i] ;
                ans1[i] = t ;
             }
       }

       void  in2(int l , int r , int c){
             c2[l] += c ;
             c2[r+1] -= c ;
       }

       void  gsum2(){
             long t = 0  ;
             for(int i = 1 ; i <= n ; i++){
                t += c2[i] ;
                ans2[i] = t ;
             }
       }

       void  change2(int x , int y , int d){
             while(top[x] != top[y]){
                  if(dep[top[x]] < dep[top[y]]){
                        x ^= y ; y ^= x ; x ^= y ;
                  }
                  in2(tid[top[x]] , tid[x] , d) ;
                  x = fa[top[x]] ;
             }
             if(x == y) return  ;
             if(dep[x] > dep[y]){
                    x ^= y ; y ^= x ; x ^= y ;
             }
             in2(tid[x]+1 , tid[y] , d) ;
       }

       void  change1(int x , int y , int d){
             while(top[x] != top[y]){
                  if(dep[top[x]] < dep[top[y]]){
                      x ^= y ; y ^= x ; x ^= y ;
                  }
                  in1(tid[top[x]] , tid[x] , d) ;
                  x = fa[top[x]] ;
             }
             if(dep[x] > dep[y]){
                  x ^= y ; y ^= x ; x ^= y ;
             }
             in1(tid[x] , tid[y] , d) ;
       }
}


class   InputReader{
        public BufferedReader  reader;
        public StringTokenizer  tokenizer;

        public InputReader(InputStream stream){
               reader = new BufferedReader(new InputStreamReader(stream), 32768) ;
               tokenizer = null ;
        }

        public String next(){
               while(tokenizer == null || ! tokenizer.hasMoreTokens()){
                        try{
                            tokenizer = new StringTokenizer(reader.readLine());
                        }catch (IOException e) {
                             throw new RuntimeException(e);
                        }
               }
               return tokenizer.nextToken();  
        }

        public int  nextInt(){
                    return Integer.parseInt(next());
        }

        public long nextLong(){
                    return Long.parseLong(next());
        }

        public double nextDouble(){
                    return  Double.parseDouble(next());
        }

}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值