启智树冲省队组Day5T3 划分
jiazhaopeng · · 个人记录
首先可以把题意转化一下:
把一棵点带权树上的
n 个点划分为A ,B 两个集合,一种划分方案的代价是:来自A 集合的代价:\sum_{i}d_i+g(A)-\sum_{x \gets y}[w_x \le w_y] ;来自B 集合的代价:\sum_{x \gets y}[w_x < w_y] 。其中x \gets y 表示x 是y 的祖先,g(A)={|A| \choose 2} ,d_i 表示i 到根的距离。总代价为两集合的代价之和。
全部在
如果点权互不相同,则容易发现取每个点的代价为
如果有点权相同的情况,则代价应该是
不过看起来如果存在祖先子孙权值相同,先取祖先好像更优。因为
每个点的
关键代码:
int fa[N], dep[N];
int a[N], b[N];
void dfs1(int cur, int faa) {
fa[cur] = faa; dep[cur] = dep[faa] + 1;
a[cur] = query(w[cur]);
add(w[cur], 1);
for (register int i = head[cur]; i; i = e[i].nxt) {
int to = e[i].to; if (to == faa) continue;
dfs1(to, cur);
}
add(w[cur], -1);
}
void dfs2(int cur, int faa) {
add(w[cur], 1);
b[cur] -= (query(ltot) - query(w[cur]));
for (register int i = head[cur]; i; i = e[i].nxt) {
int to = e[i].to; if (to == faa) continue;
dfs2(to, cur);
}
b[cur] += (query(ltot) - query(w[cur]));
}
int id[N];
inline bool cmp(const int x, const int y) {
return dep[x] - a[x] - b[x] < dep[y] - a[y] - b[y];
}
ll ans[N];
int main() {
read(n);
for (register int i =1 ; i <= n; ++i) read(w[i]), h[i] = w[i];
lsh();
for (register int i =1 ; i < n; ++i) {
int u, v; read(u), read(v);
addedge(u, v), addedge(v, u);
}
dep[0] = -1;
dfs1(1, 0);
dfs2(1, 0);
for (register int i = 1; i <= n; ++i) id[i] = i;
sort(id +1 , id + 1 + n, cmp);
ll res = 0;
for (register int i = 1; i <= n; ++i) res += b[i];
ans[n] = res;
for (register int i = 1; i <= n; ++i) {
int p = id[i];
res += dep[p] - a[p] - b[p];
ans[n - i] = res + ((1ll * i * (i - 1)) >> 1);
}
for (register int i = 0; i <= n; ++i)
printf("%lld\n", ans[i]);
return 0;
}