题目:
给你一棵个结点的树,结点带权值。让你删去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; }