题意:在一棵树上给出m个链
<u,v>
, 求出最多能够选择多少个链使得所有的链都没有交点。
根据lca自底向上贪心即可。
#include <cstring>
#include <iostream>
#include <cstdio>
#include <cmath>
#include <algorithm>
using namespace std;
#define maxn 100005
#define maxm maxn*2
int n, m;
struct node {
int v, next;
}edge[maxm];
int cnt, head[maxn];
int deep[maxn];
struct Q {
int u, v;
int lca;
int next;
bool operator < (const Q &a) const {
return deep[lca] > deep[a.lca];
}
}qu[maxm];
int cnt2, head2[maxn];
int p[maxn], fa[maxn];
bool vis[maxn];
#define find Find
int find (int x) {
return p[x] == x ? p[x] : p[x] = find (p[x]);
}
void add_edge (int u, int v) {
edge[cnt].v = v, edge[cnt].next = head[u], head[u] = cnt++;
}
void add_query (int u, int v) {
qu[cnt2].u = u, qu[cnt2].v = v, qu[cnt2].next = head2[u], head2[u] = cnt2++;
}
void LCA (int u, int father, int d) {
deep[u] = d;
p[u] = u;
fa[u] = father;
vis[u] = 1;
for (int i = head[u]; i != -1; i = edge[i].next) {
int v = edge[i].v;
if (vis[v]) continue;
LCA (v, u, d+1);
p[v] = u;
}
for (int i = head2[u]; i != -1; i = qu[i].next) {
int v = qu[i].v;
if (vis[v]) {
qu[i^1].lca = qu[i].lca = find (v);
}
}
}
void del (int u) {
vis[u] = 1;
for (int i = head[u]; i != -1; i = edge[i].next) {
int v = edge[i].v;
if (vis[v] || v == fa[u]) continue;
del (v);
}
}
void solve () {
int ans = 0;
for (int i = 0; i < cnt2; i++) {
if (vis[qu[i].u] || vis[qu[i].v]) continue;
ans++;
del (qu[i].lca);
}
printf ("%d\n", ans);
}
int main () {
while (scanf ("%d%d", &n, &m) == 2) {
cnt = cnt2 = 0;
for (int i = 1; i <= n; i++) head[i] = head2[i] = -1, vis[i] = 0;
for (int i = 1; i < n; i++) {
int u, v;
scanf ("%d%d", &u, &v);
add_edge (u, v);
add_edge (v, u);
}
for (int i = 1; i <= m; i++) {
int u, v;
scanf ("%d%d", &u, &v);
add_query (u, v);
add_query (v, u);
}
LCA (1, 1, 0);
cnt2 >>= 1;
for (int i = 0; i < cnt2; i++) {
qu[i] = qu[i<<1];
}
sort (qu, qu+cnt2);
memset (vis, 0, sizeof vis);
solve ();
}
return 0;
}