洛谷题目(cf)P13099 [FJCPC 2025] VERTeX

题目来源:https://www.luogu.com.cn/problem/P13099

`

define int long long

typedef pair<int, int> PII;

vector poi[200010]; // 邻接表存储树
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;
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但是还是无法均匀分配补差差值。

posted @ 2025-07-11 15:25  yubai111  阅读(6)  评论(0)    收藏  举报