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

  


原文地址:https://www.cnblogs.com/chengsheng/p/4836016.html