CF2143C:Max Tree题解
S1lver_W0lf · · 题解
CF2143C:Max Tree题解
题目大意:
给定一个有
构造一个从
对于每条边
整个树的值为每条边的值相加。
请求出使整个树的值最小的排列
思路
我想要每条边的值尽可能的小,但是又有一定约束性。赛时我就莫名联想到了差分约束,所以我就开始顺着这条线走下去。
对于图中的每个点,结合最小化贡献值,能够得到排列
可以发现,
在拓扑排序时,新建一个变量 nw = 1,表示现在是排列 nw,随后 nw++ 即可。
文字可能有点难以理解,接下来是代码。
代码
#include <bits/stdc++.h>
using namespace std;
constexpr int N = 150;
vector <int> e[200010];
void solve(){
int n;
cin >> n;
vector <int> d(n + 1), ans(n + 1, 0);//动态数组,方便初始化
for(int i = 1; i <= n; i++)//初始化边数组
e[i].clear();
for(int i = 1; i < n; i++){
int u, v, x, y;
cin >> u >> v >> x >> y;
//根据题意,以及 x 和 y 的值,最小化边贡献
if(x < y){
d[v]++;
e[u].push_back(v);
}
else{
d[u]++;
e[v].push_back(u);
}
}
//以下是拓扑排序部分
queue <int> q;
int nw = 1;
//将入度为 0 的节点入队
for(int i = 1; i <= n; i++)
if(!d[i])
q.push(i), ans[i] = nw++;
while(!q.empty()){
int u = q.front();
q.pop();
for(auto v : e[u])
if(!--d[v]){
//如果删去当前边后,弧头指向的节点入度为 0,则入队
q.push(v);
ans[v] = nw++;
}
}
for(int i = 1; i <= n; i++)
cout << ans[i] << " \n"[i == n];
}
int T;
int main(){
cin >> T;
while(T--){
solve();
}
return 0;
}