【Network POJ-3417】 (DFS | TARJAN| LCA | 树上差分)

传送门

题目大意:

给定无根树,N个节点,N-1条树边,和M条“附加边”;

删除一条树边和一条附加边使图不再连通,求总方案数;

/*
*Network POJ3417
*/
#include <cstdio>
#include <cstdbool>
#include <cstring>

constexpr int NN{(int)(1e5)+1},MM{(int)(1e5)<<1|1};
using llong = long long;
int h[NN],ne[MM],to[MM],d[NN],s[NN],par[NN],tot = 0,LCA[NN][NN] = {0};
_Bool vst[NN];
inline void add(int u,int v){to[tot] = v,ne[tot] = h[u],h[u] = tot++;}
int find(int u){return par[u] == u?u:par[u] = find(par[u]);}
void init(int N){
	memset(h,-1,sizeof h);tot = 0;memset(s,0,sizeof s);memset(d,0,sizeof d);
	int i;for(i = 0;i <= N;++i)par[i] = i,LCA[1][i] = 1;
}
void tarjan(int u,int fa,int N){
	int i;
	for(i = h[u];~i;i = ne[i])if(!(to[i] == fa))tarjan(to[i],u,N),par[to[i]] = u,vst[to[i]];
	for(i = 1;i <= N;++i)if(!vst[i])LCA[u][i] = find(i);	
}
void dfs(int u,int fa){
	s[u] = d[u];
	int i;
	for(i = h[i];~i;i = to[i])if(!(fa == to[i]))dfs(to[i],u),s[u]+=s[to[i]];
}
int main(void){
	int N,M;
	while(~scanf("%d%d",&N,&M) && (N || M)){
		init(N);
		int i,u,v;
		for(i = N;i-->0;add(u,v),add(v,u))scanf("%d%d",&u,&v);
		(void)tarjan(1,0,N);
		while(M--){
			scanf("%d%d",&u,&v);
			++d[u],++d[v],d[LCA[u][v]] -= 2;
		}
		dfs(1,0);
		llong ans = 0;
		for(i = 1;i <= N;++i)ans += !(s[i] >= 1)?M:(size_t)(s[i] == 1);
		printf("%lld\n",ans);
	}
	return 0;
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

XNB's Not a Beginner

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值