2015沈阳网络赛1003 Minimum Cut 树链剖分 数组维护前缀和进行区间增减

2015沈阳网络赛1003  Minimum Cut   树链剖分 数组维护前缀和进行区间增减

Minimum Cut

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


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
 
这题出题人卡了个mlogn,必须用o(m)才能过,比赛的时候线段树和树状数组都T了。。。
赛后听说o(m)秒懂。。。改成数组维护前缀和直接秒A。。。太可惜了。。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<queue>
#include<stack>
#include<vector>
#include<map>
#include<set>
#include<string>
#include<math.h>
#define REP(i,a,b) for(int i=a;i<=b;i++)
#define MS0(a) memset(a,0,sizeof(a))
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define RI(x) scanf("%d",&(x))
#define RII(x,y) scanf("%d%d",&(x),&(y))
#define RIII(x,y,z) scanf("%d%d%d",&(x),&(y),&(z))

using namespace std;

typedef long long ll;
const int maxn=20100;
const int INF=(1<<29);
const double EPS=0.00000000000001;
const double Pi=acos(-1.0);

int n,m;
int u,v,w;
vector<int> G[maxn];
int dep[maxn],son[maxn],fa[maxn],siz[maxn];
int top[maxn];
int id[maxn];
int num;
int val[maxn];
int tag[maxn];
struct Tree
{
    int u,v,w;
};
Tree tree[maxn];

void Init()
{
    MS0(son);MS0(siz);
    MS0(id);MS0(val);
    MS0(dep);MS0(tag);
}

void dfs1(int u,int f,int d)
{
    fa[u]=f;
    dep[u]=d;
    son[u]=0;
    siz[u]=1;
    for(int i=0;i<G[u].size();i++){
        int v=G[u][i];
        if(v==f) continue;
        dfs1(v,u,d+1);
        if(siz[v]>siz[son[u]]) son[u]=v;
        siz[u]+=siz[v];
    }
}

void dfs2(int u,int tp)
{
    top[u]=tp;
    id[u]=++num;
    if(son[u]) dfs2(son[u],tp);
    for(int i=0;i<G[u].size();i++){
        int v=G[u][i];
        if(v==fa[u]||v==son[u]) continue;
        dfs2(v,v);
    }
}

void update(int L,int R,int c)
{
    tag[L]+=c;
    tag[R+1]-=c;
}

void add(int u,int v,int c)
{
    while(top[u]!=top[v]){
        if(dep[top[u]]<dep[top[v]]) swap(u,v);
        update(id[top[u]],id[u],c);
        u=fa[top[u]];
    }
    if(u!=v){
        if(dep[u]>dep[v]) swap(u,v);
        update(id[u]+1,id[v],c);
    }
}

int main()
{
    //freopen("in.txt","r",stdin);
    int Tt;cin>>Tt;
    int casen=1;
    while(Tt--){
        for(int i=0;i<=n;i++) G[i].clear();
        scanf("%d%d",&n,&m);
        Init();
        for(int i=1;i<n;i++){
            scanf("%d%d",&u,&v);
            tree[i]={u,v,1};
            G[u].push_back(v);
            G[v].push_back(u);
        }
        num=0;
        dfs1(1,0,1);
        dfs2(1,1);
        for(int i=1;i<n;i++){
            if(dep[tree[i].u]>dep[tree[i].v]) swap(tree[i].u,tree[i].v);
            val[id[tree[i].v]]=tree[i].w;
        }
        for(int i=n;i<=m;i++){
            scanf("%d%d",&u,&v);
            add(u,v,1);
        }
        for(int i=1;i<=n;i++) tag[i]+=tag[i-1];
        for(int i=1;i<=n;i++) val[i]+=tag[i];
        int ans=INF;
        for(int i=1;i<n;i++){
            ans=min(ans,val[tree[i].v]);
        }
        printf("Case #%d: %d\n",casen++,ans);
    }
    return 0;
}
View Code

 

 

转载于:https://www.cnblogs.com/--560/p/4822034.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值