题目:

给你一棵个结点的树,结点带权值。让你删去2条树边使其变成3棵点权和相等的非空树。输出任意方案。


做法:

我们求出个点的点权和。如果肯定无解。
任一合法方案,删除2条边后,必定形成如下图形状的联通块,其中的点权和相同:

必定是某棵完整的子树。
所以我们从根一遍,一旦找到某棵子树和为,说明找到了,记录这棵子树的根,把子树删掉,接着处理。最后如果纪录了棵子树,说明有解。注意不能用判断,因为点权有负值,可能找到茫茫多子树。


代码:

#include <bits/stdc++.h>
#define IOS ios::sync_with_stdio(false), cin.tie(0)
#define debug(a) cout << #a ": " << a << endl
using namespace std;
typedef long long ll;
const int N = 1e6 + 7;
int n, rt, w[N], sum, dp[N];
vector<int> g[N], ans;
void dfs(int u){
    dp[u] += w[u]; 
    for (int& v : g[u]){
        dfs(v); dp[u] += dp[v];
    }
    if (dp[u] == sum) ans.push_back(u), dp[u] = 0;
}
int main(void){
    IOS;
    cin >> n;
    for (int i = 1; i <= n; ++i){
        int f; cin >> f >> w[i];
        if (f) g[f].push_back(i);
        else rt = i;
        sum += w[i];
    }
    if (sum%3 != 0){
        cout << -1 << endl; return 0;
    }
    sum /= 3;
    dfs(rt);
    if (ans.size() >= 3){
        cout << ans[0] << ' ' << ans[1] << endl;
    }else{
        cout << -1 << endl;
    }
    return 0;
}