树上搜索题解
题目链接
题目描述
给一棵 n n n 个结点的树,每个结点的权值为 w [ i ] w[i] w[i], 给出 m m m 个询问,每次询问给出一个结点 u u u,进行如下操作:
- 找树的重心
- 询问 u u u 是否是该点的子孙结点,如果是的话则删除这个点所构成的子树之外的所有点,否则删除该点所构成的子树所有点
- 最后只剩下结点
u
u
u,则结束
求删除点的序列
思路分析
由于每次是删除重心,也就是最靠近当前树的结点权值的平均数的点,所以每次结点权值减少大概为 1 2 \frac{1}{2} 21,所以大概是要删 l o g n logn logn 个点,所以可以考虑暴力,每次模拟删除过程即可。
代码
#include <bits/stdc++.h>
using namespace std;
#define int long long
typedef pair<int, int>PII;
#define x first
#define y second
void solve() {
int n, m;
cin >> n >> m;
vector<int> w(n + 1);
vector<int> f(n + 1);
int sum = 0;
for (int i = 1; i <= n; i++) {
cin >> w[i];
sum += w[i];
}
vector<vector<int>> g(n + 1);
for (int i = 2; i <= n; i++) {
int p;
cin >> p;
f[i] = p;
g[p].emplace_back(i);
}
auto dfs = [&](auto &self, int u, int fa) -> void {
for (auto v : g[u]) {
self(self, v, u);
w[u] += w[v];
}
};
dfs(dfs, 1, -1);
vector<int> ww;
ww = w;
int rsum = sum;
for (int t = 1; t <= m; t++) {
int x;
cin >> x;
sum = rsum;
w = ww;
vector<int> st(n + 1, 0);
for (int j = 1; j <= n; j++) {
int s = sum;
int p = 0;
for (int i = 1; i <= n; i++) {
if(abs(2 * w[i] - sum) < s && !st[i]) {
s = abs(2 * w[i] - sum);
p = i;
}
}
bool flag = false;
auto dfs_ = [&](auto &self, int u, int fa) -> void {
if(x == u)flag = true;
for (auto v : g[u]) {
self(self, v, u);
}
};
dfs_(dfs_, p, -1);
auto dfs_1 = [&](auto &self, int u, int k) -> void {
// cerr << u << " " << st[u] << "\n";
if(!k)st[u] -= 1;
else st[u] = 1;
// cerr << u << " " << st[u] << "\n";
for (auto v : g[u]) {
self(self, v, k);
}
};
if(flag == true) {
sum = w[p];
for (int i = 1; i <= n; i++) {
st[i] += 1;
}
dfs_1(dfs_1, p, 0);
} else {
sum -= w[p];
dfs_1(dfs_1, p, 1);
int x = p, v = w[p];
while(x != 0) {
w[x] -= v;
x = f[x];
}
}
int cnt = 0;
// cerr << p << "\n";
for (int i = 1; i <= n; i++) {
if(st[i] == 0)cnt++;
// cerr << i << "! " << st[i] << "\n";
}
cout << p << " ";
if(cnt == 1) break;
}
cout << "\n";
}
}
signed main() {
ios::sync_with_stdio(false);
cin.tie(0), cout.tie(0);
//cout << fixed << setprecision(10);
//init();
int T = 1;
//cin >> T;
while(T --) solve();
return 0;
}