Sgu507 - Treediff
题意
个点以1为根的树,其中
个点为叶节点,只有叶节点有权值
现在求每一个非叶节点的子树中,任意两个叶节点的权值差的绝对值最小是多少(如果不存在输出
分析
我们需要维护的信息是,子树中每一个叶节点的权值
当我们新加入一个叶节点的值
的时候,我们只需要找小于
中最大的值,和大于
中的最小值即可
那么我们可以用
或是
来存储已经有的叶节点权值
只需要找到
或是
中
的地址,往前一个就是比
小的最大值,往后一个就是比
大的最小值,这样每次加入一个点都更新答案即可
这里我用 来实现
代码
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
const int MAX = 5e4 + 10;
int N, M;
int a[MAX];
char s[MAX];
vector<int> g[MAX];
int siz[MAX], son[MAX];
void dfs(int u, int fa) {
siz[u] = 1;
for (auto &v: g[u])
if (v != fa) {
dfs(v, u);
siz[u] += siz[v];
if (!son[u] || siz[v] > siz[son[u]])
son[u] = v;
}
}
int vis[MAX], ans[MAX], mn = INT_MAX;//INT_MAX就是2^31 - 1
map<int, int> mp;
map<int, int>::iterator it, t;
void upd(int u, int fa, int k) {
if (u >= N - M + 1 && k == 1) {
mp[a[u]]++;
if (mp[a[u]] == 1) {//如果当前这个点只有一个, 那就往前往后找
it = mp.find(a[u]), t = it;
if (it != mp.begin()) {//往前找, 并且不是第一个的时候
it--;//前一个地址
mn = min(mn, a[u] - (*it).first);
}
it = t;
t = mp.end(); t--;//map.end()-1才是map中最后一个元素的地址
if (it != t) {//同理
it++;
mn = min(mn, (*it).first - a[u]);
}
}
else mn = 0;//如果这个权值不止一个,那么差值可以是0了
}
for (auto &v: g[u])
if (v != fa && !vis[v]) upd(v, u, k);
}
void dsu(int u, int fa, int keep) {
for (auto &v: g[u])
if (v != fa && v != son[u]) dsu(v, u, 0);
if (son[u]) dsu(son[u], u, 1), vis[son[u]] = 1;
upd(u, fa, 1);
ans[u] = mn;
if (son[u]) vis[son[u]] = 0;
if (!keep) mp.clear(), mn = INT_MAX;
}
int main() {
scanf("%d%d", &N, &M);
for (int i = 2; i <= N; i++) {
int u; scanf("%d", &u);
g[u].push_back(i); g[i].push_back(u);
}
for (int i = N - M + 1; i <= N; i++) scanf("%d", &a[i]);
dfs(1, 0);
dsu(1, 0, 0);
for (int i = 1; i <= N - M; i++) printf("%d%s", ans[i], i == N - M ? "\n" : " ");
return 0;
}