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.
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 (1≤t≤5) 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 (2≤n≤20000) and m (n−1≤m≤200000).
The following n−1 lines describe the spanning tree T and each of them contains two integers u and v corresponding to an edge.
Next m−n+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.
The first line of the input is a single integer t (1≤t≤5) 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 (2≤n≤20000) and m (n−1≤m≤200000).
The following n−1 lines describe the spanning tree T and each of them contains two integers u and v corresponding to an edge.
Next m−n+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; }