给定一棵 n 个结点的树,结点标号 1∼n 。你需要给每个点标注 0 或 1 的权值。
有若干条规则,形如 “若路径 u−v 上所有点权都是 c ,则你可获得 p 的收益” ,问最大可能的总收益。
其中c∈{0, 1}.
对每一条 c = 0 的路径和每一条 c = 1 的路径,判断它们是否冲突。
建出二分图,转化为求其最大权独立集。
用最小割求解即可。
树上 a->b 的路径与 c->d 的路径相交,等价于 lca(a, b) 在 c->d 的路径上或 lca(c, d) 在 a->b 的路径上。
树上 p 在 a->b的路径上,等价于 dist(a, p) + dist(p, b) = dist(a, b).
代码如下:
#include <bits/stdc++.h>
using namespace std;
inline int read() {
int x = 0, f = 0; char ch = getchar();
while (!isdigit(ch)) f = ch == '-', ch = getchar();
while (isdigit(ch)) x = (x << 3) + (x << 1) + (ch ^ 48), ch = getchar();
return f ? -x : x;
}
const int N = 100010, M = 200010, AA = 710, inf = 0x3f3f3f3f;
const int NN = 1410, MM = 1000100;
int sum, n, A, B, thead[N], tnex[M], tver[M], ttot = 1;
int dep[N], fa[N][20];
struct Node {
int u, v, p, fa;
};
Node a[AA], b[AA];
struct Graph {
int S, T, head[NN], nex[MM], ver[MM], f[MM], tot = 1;
int d[NN], cur[NN];
bool bfs() {
memset(d, 0, sizeof d);
queue<int> q;
q.push(S); d[S] = 1; cur[S] = head[S];
while (!q.empty()) {
int x = q.front(); q.pop();
for (int i = head[x]; i; i = nex[i]) {
int y = ver[i];
if (f[i] && !d[y]) {
d[y] = d[x] + 1;
cur[y] = head[y];
if (y == T) return true;
q.push(y);
}
}
}
return false;
}
int find(int u, int lim) {
if (u == T) return lim;
int flow = 0;
for (int i = cur[u]; i && flow < lim; i = nex[i]) {
cur[u] = i;
int y = ver[i];
if (f[i] && d[y] == d[u] + 1) {
int z = find(y, min(lim - flow, f[i]));
if (!z) d[y] = 0;
else f[i] -= z, f[i ^ 1] += z, flow += z;
}
}
return flow;
}
int dinic() {
int res = 0, flow;
while (bfs()) while ((flow = find(S, inf))) res += flow;
return res;
}
void add(int x, int y, int z) {
ver[++tot] = y; f[tot] = z; nex[tot] = head[x]; head[x] = tot;
ver[++tot] = x; f[tot] = 0; nex[tot] = head[y]; head[y] = tot;
}
};
Graph G;
void Add(int x, int y) { tver[++ttot] = y; tnex[ttot] = thead[x]; thead[x] = ttot; }
void dfs_lca(int x, int father) {
dep[x] = dep[father] + 1;
fa[x][0] = father;
for (int j = 1; j < 20; ++j) {
fa[x][j] = fa[fa[x][j - 1]][j - 1];
}
for (int i = thead[x]; i; i = tnex[i]) {
int y = tver[i];
if (y == father) continue;
dfs_lca(y, x);
}
}
int lca(int x, int y) {
if (dep[x] > dep[y]) swap(x, y); // dep[x] <= dep[y];
int depth = dep[y] - dep[x];
for (int j = 19; j >= 0; --j) {
if ((depth >> j) & 1) {
y = fa[y][j];
}
}
if (x == y) return x;
for (int j = 19; j >= 0; --j) {
if (fa[x][j] != fa[y][j]) {
x = fa[x][j]; y = fa[y][j];
}
}
return fa[x][0];
}
int dist(int x, int y) {
int p = lca(x, y);
return dep[x] + dep[y] - dep[p] * 2;
}
bool judge(int x, int y) {
int aa = a[x].u, bb = a[x].v, p1 = a[x].fa;
int c = b[y].u, d = b[y].v, p2 = b[y].fa;
if (dist(aa, p2) + dist(p2, bb) == dist(aa, bb) || dist(c, p1) + dist(p1, d) == dist(c, d)) return true;
return false;
}
int main() {
n = read(); A = read(); B = read(); G.S = NN - 1; G.T = NN - 2;
for (int i = 1; i < n; ++i) {
int u = read(), v = read();
Add(u, v); Add(v, u);
}
dfs_lca(1, 0);
for (int i = 1; i <= A; ++i) {
a[i].u = read(); a[i].v = read(); a[i].p = read();
a[i].fa = lca(a[i].u, a[i].v); sum += a[i].p;
G.add(G.S, i, a[i].p);
}
for (int i = 1; i <= B; ++i) {
b[i].u = read(); b[i].v = read(); b[i].p = read();
b[i].fa = lca(b[i].u, b[i].v); sum += b[i].p;
G.add(A + i, G.T, b[i].p);
}
for (int i = 1; i <= A; ++i) {
for (int j = 1; j <= B; ++j) {
if (judge(i, j)) {
G.add(i, A + j, inf);
}
}
}
printf("%d\n", sum - G.dinic());
return 0;
}