题意:
题目链接:http://acm.split.hdu.edu.cn/showproblem.php?pid=4912
一棵树上有m条链,要求取得最多的链,保证链与链之间的节点没有重复。
思路:
又get到新套路
对于树上任意两点之间的路径,一定会经过他们之间的LCA。
贪心的思路,很关键的一点要意识到,对于两条链,如果存在重复,应该选择LCA深度较大的,也就是里根越远的。因为深度越小灵活度越小,可能会造成重复的几率也越大。
这样,就求出所有链的LCA,然后按照深度排序,每次选择一条链,答案加1,就将该链LCA子树删除即可。
代码:
#include <bits/stdc++.h>
using namespace std;
const int MAXN = 1e5 + 10;
struct Node {
int v, w;
};
struct QNode {
int v, id;
};
int deep[MAXN];
struct Query {
int u, v, lca;
bool operator < (const Query &rhs) const {
return deep[lca] > deep[rhs.lca];
}
};
struct LCA {
int n, m, ans;
vector <Node> tree[MAXN];
vector <QNode> qtree[MAXN];
Query q[MAXN];
int pa[MAXN], fa[MAXN];
bool vis[MAXN];
void init(int n, int m) {
this->n = n;
this->m = m;
memset(vis, false, sizeof(vis));
memset(deep, 0, sizeof(deep));
for (int i = 1; i <= n; i++) pa[i] = i;
for (int i = 1; i <= n; i++) tree[i].clear();
for (int i = 1; i <= m; i++) qtree[i].clear();
}
void addEdge(int u, int v, int w) {
tree[u].push_back((Node) {v, w});
tree[v].push_back((Node) {u, w});
}
void addQuEdge(int u, int v, int id) {
q[id] = (Query){u, v, -1};
qtree[u].push_back((QNode) {v, id});
qtree[v].push_back((QNode) {u, id});
}
int Find(int x) {
return pa[x] == x ? x : pa[x] = Find(pa[x]);
}
void tarjan(int u, int pre) {
vis[u] = true;
fa[u] = pre;
for (int i = 0; i < (int)tree[u].size(); i++) {
int v = tree[u][i].v, w = tree[u][i].w;
if (vis[v]) continue;
deep[v] = deep[u] + w;
tarjan(v, u);
pa[v] = u;
}
for (int i = 0; i < (int)qtree[u].size(); i++) {
int v = qtree[u][i].v, id = qtree[u][i].id;
if (vis[v]) {
q[id].lca = Find(v);
}
}
}
void dfs(int u) {
vis[u] = true;
for (int i = 0; i < (int)tree[u].size(); i++) {
int v = tree[u][i].v;
if (vis[v] || fa[u] == v) continue;
dfs(v);
}
}
void solve() {
tarjan(1, -1);
ans = 0;
memset(vis, false, sizeof(vis));
sort(q + 1, q + 1 + m);
for (int i = 1; i <= m; i++) {
int u = q[i].u, v = q[i].v;
if (vis[u] || vis[v]) continue;
++ans;
dfs(q[i].lca);
}
printf("%d\n", ans);
}
} Lca;
int main() {
//freopen("in.txt", "r", stdin);
int n, m;
while (scanf("%d%d", &n, &m) == 2) {
Lca.init(n, m);
for (int i = 1; i < n; i++) {
int u, v;
scanf("%d%d", &u, &v);
Lca.addEdge(u, v, 1);
}
for (int i = 1; i <= m; i++) {
int u, v;
scanf("%d%d", &u, &v);
Lca.addQuEdge(u, v, i);
}
Lca.solve();
}
return 0;
}