• HDU 5452——Minimum Cut——————【树链剖分+差分前缀和】ACdream 1429——Diversion——————【树链剖分】


    Minimum Cut

    Time Limit: 3000/2000 MS (Java/Others)    Memory Limit: 65535/102400 K (Java/Others)
    Total Submission(s): 895    Accepted Submission(s): 387


    Problem Description
    Given a simple unweighted graph G (an undirected graph containing no loops nor multiple edges) with n nodes and m edges. Let T be a spanning tree of G.
    We say that a cut in G respects T if it cuts just one edges of T.

    Since love needs good faith and hypocrisy return for only grief, you should find the minimum cut of graph G respecting the given spanning tree T.
     
    Input
    The input contains several test cases.
    The first line of the input is a single integer t (1t5) which is the number of test cases.
    Then t test cases follow.

    Each test case contains several lines.
    The first line contains two integers n (2n20000) and m (n1m200000).
    The following n1 lines describe the spanning tree T and each of them contains two integers u and v corresponding to an edge.
    Next mn+1 lines describe the undirected graph G and each of them contains two integers u and v corresponding to an edge which is not in the spanning tree T.
     
    Output
    For each test case, you should output the minimum cut of graph G respecting the given spanning tree T.
     
    Sample Input
    1
    4 5
    1 2
    2 3
    3 4
    1 3
    1 4
     
    Sample Output
    Case #1: 2
     
    Source
     
     
    题目大意:给你一棵树,然后给加上m-n+1条边。问你必须切掉树上的一条边,使得图不连通最少需要切多少条边。
     
    解题思路:树链剖分。用树链剖分将树上的边都编上编号。每次加边的时候就在u--v之间加权值1。最后找到边权最小的即为答案。这里用差分前缀和来处理区间。
     
    #include<bits/stdc++.h>
    using namespace std;
    const int maxn = 1e5;
    struct Edge{
        int v,w,next;
    }edges[maxn*5];
    int head[maxn];
    int fa[maxn],dep[maxn],siz[maxn],son[maxn];
    int top[maxn],w[maxn];
    int c[maxn];
    int tot,totw;
    const int INF=0x3f3f3f3f;
    void init(){
        tot=0;
        memset(head,-1,sizeof(head));
        memset(son,-1,sizeof(son));
    }
    void addedge(int _u,int _v){
        edges[tot].v=_v;
        edges[tot].next=head[_u];
        head[_u]=tot++;
        edges[tot].v=_u;
        edges[tot].next=head[_v];
        head[_v]=tot++;
    }
    void dfs1(int u,int _fa,int _dep ){ //得到dep数组、fa数组、siz数组、son数组
        dep[u] = _dep;
        fa[u] = _fa;
        siz[u] = 1;
        for(int i=head[u]; i!=-1; i=edges[i].next){
            Edge &e = edges[i];
            if(e.v != _fa){
                dfs1(e.v,u, _dep+1);
                siz[u]+=siz[ e.v ];
                if(son[u]==-1  || siz[son[u]] <siz[e.v]){
                    son[u] = e.v;
                }
            }
        }
    }
    void dfs2(int u,int _top){  //得到top数组、w数组
        top[u]=_top;
        w[u]=totw++;
        if(son[u]!=-1){
            dfs2(son[u],_top);
            for(int i=head[u]; i != -1; i = edges[i].next){
                Edge &e = edges[i];
                if(e.v != fa[u]&&e.v!=son[u]){
                    dfs2(e.v,e.v);
                }
            }
        }
    }
    void update(int u,int v,int val){   //修改u---v路径上的权值
        int f1=top[u],f2=top[v];    //找到u,v所在重链的链头
        while(f1!=f2){  //处理不在同一条重链上的情况
            if(dep[f1]<dep[f2]){
                swap(f1,f2);
                swap(u,v);
            }
            c[w[f1]] +=val; //这里用的是差分前缀和的方法实现
            c[w[u]+1]-=val;
            u=fa[f1];
            f1=top[u];
        }
        if(dep[u]>dep[v]){   //让u处于靠近根的位置
            swap(u,v);
        }
        c[w[son[u]]]+=val;  //处理在同一条重链上的情况
        c[w[v]+1]-=val;
    }
    int main(){
        int t,n,m,cnt=0;
        scanf("%d",&t);
        while(t--){
            init();
            scanf("%d%d",&n,&m);
            int a,b;
            for(int i=1;i<=n-1;i++){
                scanf("%d%d",&a,&b);
                addedge(a,b);
            }
            dfs1(1,-1,1);
            totw=1;
            dfs2(1,1);
            memset(c,0,sizeof(c));
            for(int i=1;i<=m-n+1;i++){
                scanf("%d%d",&a,&b);
                update(a,b,1);
            }
            for(int i=1;i<=n;i++){
                c[i]+=c[i-1];
            }
            int ans=INF;
            for(int i=1;i<=n;i++){
                if(c[i]!=0&&c[i]){
                    ans=min(ans,c[i]);
                }
            }
            printf("Case #%d: %d
    ",++cnt,ans+1);
        }
        return 0;
    }
    

      

    Diversion

    Time Limit: 2000/1000MS (Java/Others)    Memory Limit: 128000/64000KB (Java/Others)
    Submit Status

    Problem Description

          The kingdom of Farland has n cities connected by m bidirectional roads. Some of the roads are paved with stone, and others are just country roads. The capital of the kingdom is the city number 1. The roads are designed in such a way that it is possible to get from any city to any other using only roads paved with stone, and the number of stone roads is minimal possible. The country roads were designed in such a way that if any stone road is blocked or destroyed it is still possible to get from any city to any other by roads.
    ​      Let us denote the number of stone roads needed to get from city u to city v as s(u, v). The roads were created long ago and follow the strange rule: if two cities u and v are connected by a road (no matter,stone or country), then either s(1, u) + s(u, v) = s(1, v ) or s(1, v ) + s(v, u) = s(1, u).
    ​      The king of Edgeland is planning to attack Farland. He is planning to start his operation by destroying some roads. Calculations show that the resources he has are enough to destroy one stone road and one country road. The king would like to destroy such roads that after it there were at least two cities in Farland not connected by roads any more.
    ​      Now he asks his minister of defense to count the number of ways he can organize the diversion. But the minister can only attack or defend, he cannot count. Help him!

    Input

          The first line of the input file contains n and m — the number of cities and roads respectively (3 ≤ n ≤ 20 000, m ≤ 100 000). The following m lines describe roads, each line contains three integer numbers — the numbers of cities connected by the corresponding road, and 1 for a stone road or 0 for a country road. No two cities are connected by more than one road, no road connects a city to itself.

    Output

          Output one integer number — the number of ways to organize the diversion.

    Sample Input

    6 7
    1 2 1
    2 3 1
    1 4 0
    3 4 1
    4 5 1
    3 6 0
    5 6 1

    Sample Output

    4


    解释:这个题目跟上面那个基本一样,只是最后让求的结果略有不同。这个题目问只同时删掉树上一条边,和新加的边能让图不连通的方式有多少种。那么只需要统计最后边权为1的边有多少条即可。


    #include<bits/stdc++.h>
    using namespace std;
    const int maxn = 1e5;
    struct Edge{
        int v,w,next;
    }edges[maxn*5];
    struct Country{
        int x,y;
    }countrys[maxn];
    int head[maxn];
    int fa[maxn],dep[maxn],siz[maxn],son[maxn];
    int top[maxn],w[maxn];
    int c[maxn];
    int tot,totw;
    const int INF=0x3f3f3f3f;
    void init(){
        tot=0;
        memset(head,-1,sizeof(head));
        memset(son,-1,sizeof(son));
    }
    void addedge(int _u,int _v){
        edges[tot].v=_v;
        edges[tot].next=head[_u];
        head[_u]=tot++;
        edges[tot].v=_u;
        edges[tot].next=head[_v];
        head[_v]=tot++;
    }
    void dfs1(int u,int _fa,int _dep ){ //得到dep数组、fa数组、siz数组、son数组
        dep[u] = _dep;
        fa[u] = _fa;
        siz[u] = 1;
        for(int i=head[u]; i!=-1; i=edges[i].next){
            Edge &e = edges[i];
            if(e.v != _fa){
                dfs1(e.v,u, _dep+1);
                siz[u]+=siz[ e.v ];
                if(son[u]==-1  || siz[son[u]] <siz[e.v]){   //得到u的重儿子
                    son[u] = e.v;
                }
            }
        }
    }
    //top[i]表示i节点所在重链的链头节点、w[i]表示i节点的父边在线段中的位置
    void dfs2(int u,int _top){  //得到top数组、w数组
        top[u]=_top;
        w[u]=totw++;
        if(son[u]!=-1){
            dfs2(son[u],_top);
            for(int i=head[u]; i != -1; i = edges[i].next){
                Edge &e = edges[i];
                if(e.v != fa[u]&&e.v!=son[u]){
                    dfs2(e.v,e.v);
                }
            }
        }
    }
    void update(int u,int v,int val){   //修改u---v路径上的权值
        int f1=top[u],f2=top[v];    //找到u,v所在重链的链头
        while(f1!=f2){  //处理不在同一条重链上的情况
            if(dep[f1]<dep[f2]){
                swap(f1,f2);
                swap(u,v);
            }
            c[w[f1]] +=val; //这里用的是差分前缀和的方法实现
            c[w[u]+1]-=val;
            u=fa[f1];
            f1=top[u];
        }
        if(dep[u]>dep[v]){   //让u处于靠近根的位置
            swap(u,v);
        }
        c[w[son[u]]]+=val;  //处理在同一条重链上的情况
        c[w[v]+1]-=val;
    }
    int main(){
        int n,m,cnt=0,mm;
        while( scanf("%d%d",&n,&m)!=EOF){
            mm=0;
            init();
            int a,b,cc;
            for(int i=1;i<=m;i++){
                scanf("%d%d%d",&a,&b,&cc);
                if(cc==1)
                    addedge(a,b);
                else  countrys[++mm].x=a,countrys[mm].y=b;
            }
            dfs1(1,-1,1);
            totw=1;
            dfs2(1,1);
            memset(c,0,sizeof(c));
            for(int i=1;i<=mm;i++){
                a=countrys[i].x;
                b=countrys[i].y;
                update(a,b,1);
            }
            for(int i=1;i<=n;i++){
                c[i]+=c[i-1];
            }
            int ans=0;
            for(int i=2;i<=n;i++){
                if(c[i]==1){
                    ans++;
                }
            }
            printf("%d
    ",ans);
        }
        return 0;
    }
    

      

    
    
  • 相关阅读:
    hdu 3032 Nim or not Nim? (SG函数博弈+打表找规律)
    HDU 2147 kiki's game(博弈)
    C++学习47 文件的概念 文件流类与文件流对象 文件的打开与关闭
    C++学习46 getline()函数读入一行字符 一些与输入有关的istream类成员函数
    C++学习45 流成员函数put输出单个字符 cin输入流详解 get()函数读入一个字符
    C++学习44 格式化输出,C++输出格式控制
    C++学习43 输入输出有关的类和对象
    C++学习42 输入和输出的概念
    C++学习41 exception类
    C++学习40 抛出自己的异常
  • 原文地址:https://www.cnblogs.com/chengsheng/p/4836016.html
Copyright © 2020-2023  润新知