CF1296F Berland Beauty

题面

给出一颗树上地方边和一些限制条件:两点间路径上边权的最小值,求出一个合法的边权方案

把限制条件按最小值从大到小排序,依次处理,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;
}
原文地址:https://www.cnblogs.com/whx666/p/12670308.html