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