HDU5452 – Minimum Cut(LCA+DFS统计)

HDU5452

【题意】一张图G中有一颗生成树T,问最少删除多少条边能使得图不连通,删除的边中必须有且仅有一条包含生成树T中的边。

【分析】对于一个生成树上的点x,如果删除他则需要把以他为根的子树中连在外面的边数都删掉,那么这就是断开x处的花费,那么只要算出每个子树的话费即可。然后关键就是求出每个子树连向外面的边数即可:用sum[]记录。对于不在生成树中的边(u,v)由于是无向的,他会带给点u和点v各一个贡献,所以先把sum[u]++,sum[v]++,但是这样就多算了(u,v)都在同一颗子树的时候的sum值,只要让sum[lca(u,v)] -= 2就可以了(由于数据比较水,不减去也能AC,但是是错的)。然后DFS统计一遍,累加起来每个子树的sum值,像前缀和一样就是断开每颗子树需要断开的边数了。

复杂度n*log(n)+m

网赛的时候用网络流+输入挂竟然是WA,而不是超时,导致我一直往网络流想,根本没想其他方法,唉,其实蛮水的。

【AC CODE】421ms

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
#define rep(i,a,n) for(int i = a; i < n; i++)
#define repe(i,a,n) for(int i = a; i <= n; i++)
#define per(i,n,a) for(int i = n; i >= a; i--)
#define clc(a,b) memset(a,b,sizeof(a))
const int INF = 0x3f3f3f3f, MAXN = 20000+10, MAXM = 200000*2+10, MAXIN = 10000;
char buf[MAXIN], *ps = buf, *pe = buf+1;
inline void rnext(){
	if(++ps == pe) pe = (ps = buf)+fread(buf,sizeof(char),sizeof(buf)/sizeof(char),stdin);
}
template <class T>
inline bool in(T &ans)
{
	ans = 0;
	T f = 1;
	if(ps == pe) return false;
	do{ rnext(); if('-' == *ps) f = -1;} while(!isdigit(*ps) && ps != pe);
	if(ps == pe) return false;
	do{ ans = (ans<<1)+(ans<<3)+*ps-48;rnext();}while(isdigit(*ps) && ps != pe);
	ans *= f;
	return true;
}
int head[MAXN], tol,nxt[MAXM],to[MAXM],sum[MAXN];
inline void add_edge(int u, int v)
{
	nxt[tol] = head[u], to[tol] = v;
	head[u] = tol++;
}
int cnt, ft[MAXN], d[MAXN<<1],num[MAXN<<1];
void dfs(int u, int deep, int fa)
{
	ft[u] = cnt;
	d[cnt] = deep, num[cnt++] = u;
	for(int i = head[u]; ~i; i = nxt[i])
	{
		int v = to[i];
		if(fa == v) continue;
		dfs(v,deep+1,u);
		d[cnt] = deep, num[cnt++] = u;
	}
}
int dp[MAXN<<1][21], dp_num[MAXN<<1][21];
void st_init()
{
	rep(i,0,cnt) dp[i][0] = d[i], dp_num[i][0] = num[i];
	for(int j = 1; (1<<j) <= cnt; j++)
	{
		for(int i = 0; i+(1<<j)-1 < cnt; i++)
		{
			if(dp[i][j-1] < dp[i+(1<<(j-1))][j-1])
			{
				dp[i][j] = dp[i][j-1];
				dp_num[i][j] = dp_num[i][j-1];
			}
			else
			{
				dp[i][j] = dp[i+(1<<(j-1))][j-1];
				dp_num[i][j] = dp_num[i+(1<<(j-1))][j-1];
			}
		}
	}
}
int st_query(int x, int y)
{
	if(x > y) swap(x,y);
	int k = 0;
	while((1<<(k+1)) <= y-x+1) k++;
	if(dp[x][k] <= dp[y-(1<<k)+1][k]) return dp_num[x][k];
	return dp_num[y-(1<<k)+1][k];
}
void lca_init(int rt)
{
	cnt = 0;
	dfs(rt,0,-1);
	st_init();
}
int lca_query(int x, int y)
{
	return st_query(ft[x],ft[y]);
}
void dfs(int u, int fa)
{
	for(int i = head[u]; ~i; i = nxt[i])
	{
		int v = to[i];
		if(v == fa) continue;
		dfs(v,u);
		sum[u] += sum[v];
	}
}

int main()
{
#ifdef SHY
	freopen("d:\\1.txt", "r", stdin);
#endif
	int t,count = 0;
	in(t);
	while(t--)
	{
		int n,m;
		in(n),in(m);
		clc(head,-1);
		tol = 0;
		clc(sum,0);
		rep(i,1,n)
		{
			int u,v;
			in(u),in(v);
			add_edge(u,v);
			add_edge(v,u);
		}
		lca_init(1);
		rep(i,0,m-n+1)
		{
			int u,v;
			in(u),in(v);
			sum[u]++,sum[v]++;
			sum[lca_query(u,v)] -= 2;
		}
		dfs(1,0);
		int ans = INF;
		repe(i,2,n) ans = min(ans,sum[i]+1);
		printf("Case #%d: %d\n", ++count,ans);
	}
	return 0;
}
/*
1
11 22
1 2
2 3
2 4
2 5
2 6
1 7
7 8
7 9
7 10
7 11
3 4
4 5
5 6
3 5
3 6
4 8
6 11
8 9
8 10
9 10
9 11
10 11
*/

 

发表评论

邮箱地址不会被公开。 必填项已用*标注

请输入正确的验证码