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 (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
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
#define INF 0x3f3f3f3f
const int N = 80010;
const int M = 26;
struct Edge
{
int from, to;
int nt;
} edge[2*N];
int head[N],cnt;
void add_edge(int u, int v){
edge[cnt].from = u;
edge[cnt].to = v;
edge[cnt].nt = head[u];
head[u] = cnt++;
}
//tot:时间戳,ver:节点编号 dep:深度 in:点编号位置
int tot,ver[2*N], dep[2*N], in[N],out[N];
void dfs(int x ,int pre){
ver[++tot] = x;
in[x] = tot;
for(int i=head[x]; i!=-1; i=edge[i].nt){
Edge& e=edge[i];
if(e.to==pre)continue;
dep[e.to]=dep[x]+1;
dfs(e.to,x);
ver[++tot] = x;//从子树回来
}
out[x]=tot;
}
int dp[2*N][M]; //数组开到2*N,因为遍历后序列长度为2*n-1
void ST(int n)
{
for(int i=1; i<=n; i++)dp[i][0] = ver[i];//维护真实id
for(int j=1; (1<<j)<=n; j++){
for(int i=1; i+(1<<j)-1<=n; i++){
int a = dp[i][j-1] , b = dp[i+(1<<(j-1))][j-1];
dp[i][j] = dep[a]<dep[b]?a:b;
}
}
}
//中间部分是交叉的。
int RMQ(int l,int r)
{
int k=0;
while((1<<(k+1))<=r-l+1) k++;
int a = dp[l][k], b = dp[r-(1<<k)+1][k];
return dep[a]<dep[b]?a:b;
}
int LCA(int u ,int v)
{
int x = in[u] , y = in[v];
if(x > y) swap(x,y);
int res = RMQ(x,y);
return res;
}
int num[N];
int DFS(int u,int fa)
{
for(int i = head[u]; ~i; i = edge[i].nt) {
int v = edge[i].to;
if(v == fa)continue;
DFS(v, u);
num[u]+=num[v];
}
return 0;
}
void init()
{
memset(head,-1,sizeof(head));
memset(num,0,sizeof(num));
cnt =tot=0;
}
/*
1
7 10
1 2
2 3
3 4
1 5
5 6
6 7
1 4
2 4
1 7
5 7
*/
int main()
{
int t;
int cas=0;
int n, m;
scanf("%d",&t);
while(t--){
init();
scanf("%d%d",&n,&m);
int u, v;
for(int i = 0; i < n-1; i++){
scanf("%d%d",&u,&v);
add_edge(u, v);
add_edge(v, u);
}
dfs(1,0);
ST(tot);
// printf("tot:%d\n",tot);
// for(int i=1;i<=tot;i++) printf("i:%d %d\n",i,ver[i]);
for(int i = n; i <= m; i++)
{
scanf("%d%d",&u,&v);
int tt = LCA(u, v);
//printf("u:%d v:%d inu:%d inv:%d tt:%d\n",u,v,in[u],in[v],tt);
num[u]++;
num[v]++;
num[tt]-=2;//一条边两个端点 贡献为2
}
DFS(1, 1);
int ans = INF;
for(int i = 2; i <= n; i++)
{
ans = min(ans, num[i]+1);
// printf("i:%d num:%d\n",i,num[i]);
}
printf("Case #%d: %d\n",++cas,ans);
}
return 0;
}