洛谷题目(cf)P13099 [FJCPC 2025] VERTeX
题目来源:https://www.luogu.com.cn/problem/P13099
`
define int long long
typedef pair<int, int> PII;
vector
int deepnum[200010]; // 记录每个节点的深度
int idxwei[200010]; // 记录每个节点的权值
int jminnum = 1, jminidx = 1; // 记录奇数深度的最小权值
int ominnum = INT_MAX, ominidx = 1; // 记录偶数深度最小权值
bool sgidx[200010]; // 记录该节点是否已被访问过
// BFS预处理每个节点的深度
void bfs(int start) {
queue
q.push(start);
deepnum[start] = 1;
while (!q.empty()) {
int u = q.front(); q.pop();
for (auto& v : poi[u]) {
int next = v.first;
if (deepnum[next] == 0) {
deepnum[next] = deepnum[u] + 1;
q.push(next);
}
}
}
}
// DFS计算每个节点的权值
void dfs(int start, int weis) {
idxwei[start] = weis;
sgidx[start] = true;
for (auto& v : poi[start]) {
if (sgidx[v.first]) continue;
int npoi = v.first;
int alwei = v.second;
idxwei[npoi] = alwei - weis; // 更新当前节点权值
if (deepnum[npoi] % 2 == 0) {
if (idxwei[npoi] < ominnum) {
ominnum = idxwei[npoi];
ominidx = npoi;
}
}
else {
if (idxwei[npoi] < jminnum) {
jminnum = idxwei[npoi];
jminidx = npoi;
}
}
if (poi[npoi].size()) {
dfs(npoi, idxwei[npoi]);
}
}
}
signed main() {
int n;
cin >> n;
for (int i = 0; i < n - 1; i++) {
int u, v, w;
cin >> u >> v >> w;
poi[u].push_back({ v, w });
poi[v].push_back({ u, w });
}
bfs(1); // 预处理每个节点的深度
dfs(1, 1); // 从根节点1开始,假设根节点权值为1
// 判断是否有解
if (jminnum < 0 && ominnum < 0) {
cout << "NO" << endl;
}
else {
// 调整权值使得所有节点权值都为正
if (jminnum < 0) {
int dj = 1 - jminnum; // 补差值
if (ominnum - dj <= 0) {
cout << "NO" << endl;
}
else {
cout << "YES" << endl;
for (int i = 1; i <= n; i++) {
if (deepnum[i] % 2 == 0) {
idxwei[i] -= dj; // 偶数深度,减少补差
}
else {
idxwei[i] += dj; // 奇数深度,增加补差
}
}
for (int i = 1; i <= n; i++) {
cout << idxwei[i] << " ";
}
}
}
else if (ominnum < 0){
int dj = 1 - ominnum; // 补差值
if (jminnum - dj <= 0) {
cout << "NO" << endl;
}
else {
cout << "YES" << endl;
for (int i = 1; i <= n; i++) {
if (deepnum[i] % 2 == 0) {
idxwei[i] += dj; // 偶数深度,增加补差
}
else {
idxwei[i] -= dj; // 奇数深度,减少补差
}
}
for (int i = 1; i <= n; i++) {
cout << idxwei[i] << " ";
}
}
}
else {
cout << "YES" << endl;
for (int i = 1; i <= n; i++) {
cout << idxwei[i] << " ";
}
}
}
return 0;
}`
核心思路:设根节点为1,(想设x也没问题),然后递推所有节点的权值,记录所有节点中最小权值观察是否是正整数,不是的话再遍历整棵树一次把所有节点一个个改就行了,最坏情况是10^6以内,包过
debug过程:
第一次debug:将代码修改为int jminnum = INT_MAX, jminidx = 1; // 记录奇数深度的最小权值 int ominnum = INT_MAX, ominidx = 1; // 记录偶数深度最小权值原来均初始化为1,但是考虑到如果没有任何权值小于1的话,可能这个1会干扰、凭空创造个小值,因此修改成MAX;
第二次debug:增加了对jminnum和ominnum均大于0情况的判别,此前只有两者均小于0、两个中有一个小于0、两者平均值小于等于0的情况,均大于0时不需要再做加减,直接输出就可以;
第三次debug:增开#define int long long以及signed main();
第四次debug:修正将两者平均值小于等于0的条件用于判别YES or NO的想法,因为发现当,如-4、5时,两者平均值大于0但是还是无法均匀分配补差差值。

浙公网安备 33010602011771号