题目链接
https://codeforces.com/problemset/problem/1296/F
题意
给你一颗共有 N 个节点的树,再给你N - 1条边,你不知道这些边的边权,但是你有 M 条信息,每条信息将告诉你从 U 到 V 的所有边中最小值为 W,现要求你构造出这N - 1条边的边权。
思路
以节点1为树根建树,我们先对 M 条信息中每条路径上的最小边权W从大到小排序,然后从每个U,V点出发直到到达它们的最近公共祖先,在沿途中若遇到某条边有边权且大于W,则无法构建,否则把该边权设为W。M条信息都操作完后输出答案即可。
AC代码
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int INF = 1000000;
typedef pair<int,int> pii;
const int maxn = 5500;
int d[maxn], far[maxn], ans[maxn], val_pre[maxn] , index_pre[maxn];
vector<pii> G[maxn]; //secon表示这条边是第几条。
struct node{
int u, v, w;
bool operator <(const node & b) const{
return w > b.w;
}
} a[maxn];
void dfs(int v, int last){
d[v] = d[last] + 1;
far[v] = last;
for(auto u : G[v]){
if(u.first == last) continue;
dfs(u.first, v);
index_pre[u.first] = u.second;
}
}
bool check(int u, int v, int w){
int mi = INF;
if(d[u] < d[v]) swap(u, v);
while(d[u] != d[v]) // 先把深度大的走到同一深度
{
if(val_pre[u] == INF)
val_pre[u] = w;
mi = min(mi, val_pre[u]);
u = far[u];
}
while(u != v)//再走到同一节点
{
if(val_pre[u] == INF) val_pre[u] = w;
mi = min(val_pre[u] , mi);
u = far[u];
if(val_pre[v] == INF) val_pre[v] = w;
mi = min(val_pre[v] , mi);
v = far[v];
}
return mi == w;
}
int main()
{
std::ios::sync_with_stdio(false);
int n, m;
cin >> n;
for(int i = 1;i <= n;i++) val_pre[i] = INF;
for(int i = 1;i <= n - 1;i++)
{
int u, v;
cin >> u >> v;
G[v].push_back({u,i});
G[u].push_back({v,i});
}
dfs(1, 0);
cin >> m;
for(int i = 1;i <= m;i++) cin >> a[i].u >> a[i].v >> a[i].w;
sort(a + 1, a + m + 1);
for(int i = 1;i <= m;i++)
{
if(!check(a[i].u, a[i].v, a[i].w)){
cout << -1 << endl;
return 0;
}
}
for(int i = 2;i <= n;i++){
ans[index_pre[i]] = val_pre[i];
}
for(int i = 1;i < n;i++) cout << ans[i] << " ";
return 0;
}