给出一颗树上地方边和一些限制条件:两点间路径上边权的最小值,求出一个合法的边权方案
把限制条件按最小值从大到小排序,依次处理,mn记录的每条边可能的最小值
对于每个条件:
枚举两点之间的边(LCA向上跳,数据范围小一步一步跳就行)
由于限制条件已经按值从大到小排序,被之前路径覆盖的边的最小值无法改变(否则不满足之前的某一个条件)
如果这条路径上有一条边未被覆盖(标记),则这个条件可以满足,并将路径上的未被覆盖边的mn修改为当前值,答案直接将mn数组输出
答案输出要按照边的输入顺序,由链式前向心的存图原理可以推得
#include <bits/stdc++.h>
#define il inline
#define re register
#define int long long
using namespace std;
il void read (int &x) {
char ch = getchar(); x = 0;
while (!isdigit(ch)) ch = getchar();
while (isdigit(ch)) x = x * 10 + ch - 48, ch = getchar();
}
il int Max (int a, int b) { return a > b ? a : b; }
const int N = 5010;
int n, m, c, fa[N], dfn[N], mn[N], num[N];
int cnt, to[N << 1], nxt[N << 1], h[N];
inline void add (int u, int v) { to[++cnt] = v, nxt[cnt] = h[u], h[u] = cnt; }
void dfs (int u, int la) {
dfn[u] = ++c; fa[u] = la;
for (int i = h[u]; i; i = nxt[i])
if (to[i] != la) num[to[i]] = i >> 1, dfs (to[i], u);
}
struct q {
int u, v, len;
bool operator < (const q &x) const { return len > x.len; }
} a[N];
signed main() {
read (n); cnt = 1;
for (int i = 1, u, v; i < n; ++i)
read (u), read (v), add (u, v), add (v, u);
dfs (1, 0); read (m);
for (int i = 1; i <= m; ++i)
read (a[i].u), read (a[i].v), read (a[i].len);
sort (a + 1, a + m + 1); for (int i = 1; i < n; ++i) mn[i] = 1;
for (int i = 1; i <= m; ++i) {
int x = a[i].u, y = a[i].v;
if (dfn[x] < dfn[y]) swap (x, y);
bool ok = 0;
while (dfn[x] > dfn[y]) {
if (mn[num[x]] <= a[i].len) mn[num[x]] = a[i].len, ok = 1; x = fa[x];
} while (x != y) {
if (mn[num[y]] <= a[i].len) mn[num[y]] = a[i].len, ok = 1; y = fa[y];
} if (!ok) return puts ("-1"), 0;
} for (int i = 1; i < n; ++i) printf ("%d ", mn[i]);
return 0;
}