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

传送门

题目大意:

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

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

/*
*Network POJ3417
*/
#include 
#include 
#include 

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;
}

你可能感兴趣的:(深度优先,算法)