[Question Solution] Niu Ke 206091: The Little Prince

The original question Portal
A correct violent idea is to traverse the tree, and then for each point, break the edge between it and its father. Then take a look, edge set E 2 E2How many lines in E 2 connect the two connected blocks, count the number ascnt cntcnt

  • cnt = cnt = 0 0 cnt=0 , indicatingE 2 E2Each side in E 2 can be selected, and the answer is accumulated bymmm
  • cnt = cnt = 1 1 cnt=1 , then you can only cut off that side, and the answer will add up to 1
  • c n t > 1 cnt>1 cnt>1 , no edges can be broken

How to count this cnt cntc n t ?
It can be violently combined, but we can make a difference
on thetree.For anE 2 E2Edge in E 2 (u, v) (u, v)( u ,v )

++delta[u],++delta[v],delta[lca(u,v)]-=2

Direct statistics

There is a saying, "Ten years of OI, two games are empty, don’t open ll see your ancestors", but once thought that I also had a day of this pitfall. If I didn’t open ll, I just
lost 60 points.

Code:

#include <bits/stdc++.h>
#define maxn 200010
#define int long long
using namespace std;
struct Edge{
    
    
	int to, next;
}edge[maxn << 1];
int num, head[maxn], delta[maxn], d[maxn], fa[maxn][25], n, m, ans;

inline int read(){
    
    
	int s = 0, w = 1;
	char c = getchar();
	for (; !isdigit(c); c = getchar()) if (c == '-') w = -1;
	for (; isdigit(c); c = getchar()) s = (s << 1) + (s << 3) + (c ^ 48);
	return s * w;
}

void addedge(int x, int y){
    
     edge[++num] = (Edge){
    
    y, head[x]}, head[x] = num; }

void build(int u, int pre){
    
    
	d[u] = d[pre] + 1, fa[u][0] = pre;
	for (int i = 0; fa[u][i]; ++i) fa[u][i + 1] = fa[fa[u][i]][i];
	for (int i = head[u]; i; i = edge[i].next){
    
    
		int v = edge[i].to;
		if (v != pre) build(v, u);
	}
}

int lca(int u, int v){
    
    
	if (d[u] < d[v]) swap(u, v);
	for (int i = 20; i >= 0; --i) if (d[u] - (1 << i) >= d[v]) u = fa[u][i];
	if (u == v) return u;
	for (int i = 20; i >= 0; --i)
		if (fa[u][i] != fa[v][i]) u = fa[u][i], v = fa[v][i];
	return fa[u][0];
}

void dfs(int u, int pre){
    
    
	for (int i = head[u]; i; i = edge[i].next){
    
    
		int v = edge[i].to;
		if (v == pre) continue;
		dfs(v, u);
		delta[u] += delta[v];
	}
	if (u == 1) return;
	if (!delta[u]) ans += m;
	else if (delta[u] == 1) ++ans;
}

signed main(){
    
    
	freopen("pa.in", "r", stdin);
	freopen("pa.out", "w", stdout);
	n = read(), m = read();
	for (int i = 1; i < n; ++i){
    
    
		int x = read(), y = read();
		addedge(x, y), addedge(y, x);
	}
	build(1, 0);
	for (int i = 1; i <= m; ++i){
    
    
		int x = read(), y = read(), Lca = lca(x, y);
		++delta[x], ++delta[y], delta[Lca] -= 2;
	}
	dfs(1, 0);
	printf("%lld\n", ans);
	return 0;
}

Guess you like

Origin blog.csdn.net/ModestCoder_/article/details/108617676