题意就是求一棵树以每个内节点为根的子树中所有叶子节点的权值差的最小值, 做法就是对每个子树维护一颗平衡树
然后向上递推合并时用启发式。。。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cstdlib>
using namespace std;
inline int read() {//used to read 32bit positive integer
char c = getchar();
while (!isdigit(c)) c = getchar();
int x = 0;
while (isdigit(c)) {
x = x * 10 + c - '0';
c = getchar();
}
return x;
}
const int N = 50005;
const int M = 60015;
const int INF = 2147483647;
int root[N], fa[N], W[N];
int r[N], v[N], ch[N][2], sz[N];
int it, n, m, E;
int head[N], to[N << 1], next[N << 1], dp[N];
inline void addEdge(int u, int v) {
to[E] = v, next[E] = head[u], head[u] = E++;
}
void init() {
it = 1;
E = 0;
memset(head, -1, sizeof(head));
memset(root, 0, sizeof(root));
}
int find(int u) {
return fa[u] == u ? u : fa[u] = find(fa[u]);
}
#define lch ch[rt][0]
#define rch ch[rt][1]
inline void push_up(int rt) {
sz[rt] = sz[lch] + sz[rch] + 1;
}
inline int cmp(int rt, int x) {
if (v[rt] == x) return -1;
else if (x < v[rt])
return 0;
else
return 1;
}
void rotate(int& rt, int d) {
int t = ch[rt][d ^ 1];
ch[rt][d ^ 1] = ch[t][d];
ch[t][d] = rt;
push_up(rt);
push_up(t);
rt = t;
}
void insert(int& rt, int x, bool flag) { //falg == 0 x is a number otherwise...
if (!rt) {
if (!flag) {
rt = it++;
v[rt] = x;
r[rt] = rand();
lch = rch = 0;
sz[rt] = 1;
}
else {
rt = x;
sz[rt] = 1;
}
}
else {
int d = ((flag ? v[x] : x) < v[rt] ? 0 : 1);
insert(ch[rt][d], x, flag);
if (r[ch[rt][d]] > r[rt])
rotate(rt, d ^ 1);
}
push_up(rt);
}
int kth(int rt, int k) {
if (!rt || k <= 0 || k > sz[rt]) return 0;
int t = sz[rch] + 1;
if (k == t)
return v[rt];
else if (k < t)
return kth(rch, k);
else
return kth(lch, k - t);
}
void remove(int& rt, int x) {
int d = cmp(rt, x);
if (d == -1) {
if (lch && rch) {
int d2 = r[lch] > r[rch] ? 0 : 1;
rotate(rt, d2 ^ 1);
remove(ch[rt][d2 ^ 1], x);
push_up(rt);
}
else {
rt = lch ? lch : rch;
}
}
else {
remove(ch[rt][d], x);
push_up(rt);
}
}
/*
int pred(int rt, int x) {
if (!rt) return INF;
else if (x > v[rt]) {
int res = pred(rch, x);
if (res == INF) return v[rt];
return res;
}
else
return pred(lch, x);
}*/
int pred(int rt, int x) {
if (!rt) return INF;
if (x == v[rt]) return x;
else if (x > v[rt]) {
int res = pred(rch, x);
if (res == INF) return v[rt];
return res;
}
else
return pred(lch, x);
}
/*
int succ(int rt, int x) {
if (!rt) return INF;
else if (x < v[rt]) {
int res = succ(lch, x);
if (res == INF) return v[rt];
return res;
}
else
return succ(rch, x);
}*/
int succ(int rt, int x) {
if (!rt) return INF;
if (x == v[rt]) return x;
else if (x < v[rt]) {
int res = succ(lch, x);
if (res == INF) return v[rt];
return res;
}
else
return succ(rch, x);
}
int tmp;
void mergeto(int ot, int& rt) {
if (!ot) return;
mergeto(ch[ot][0], rt);
mergeto(ch[ot][1], rt);
ch[ot][0] = ch[ot][1] = 0;
int t = pred(rt, v[ot]);
if (t != INF)
tmp = min(tmp, v[ot] - t);
t = succ(rt, v[ot]);
if (t != INF)
tmp = min(tmp, t - v[ot]);
insert(rt, ot, 1);
}
void dfs(int u) {
int omax = 0;
int id = -1, son = 0;
for (int i = head[u]; i != -1; i = next[i]) {
int v = to[i];
dfs(v);
if (sz[root[v]] > omax) {
omax = sz[root[v]];
id = v;
}
son++;
}
if (u >= n - m + 1) return;
root[u] = root[id];
if (son == 1) {
dp[u] = dp[id];
return;
}
else {
tmp = INF;
dp[u] = dp[id];
for (int i = head[u]; i != -1; i = next[i]) {
int v = to[i];
if (v == id) continue;
dp[u] = min(dp[u], dp[v]);
mergeto(root[v], root[u]);
}
dp[u] = min(dp[u], tmp);
}
}
int main() {
int u, v;
scanf("%d%d", &n, &m);
init();
for (int i = 2; i <= n; i++) {
scanf("%d", &u);
addEdge(u, i);
}
for (int i = n - m + 1; i <= n; i++) {
scanf("%d", W + i);
dp[i] = INF;
insert(root[i], W[i], 0);
}
dfs(1);
for (int i = 1; i <= n - m; i++)
printf("%d ", dp[i]);
puts("");
return 0;
}