给你一棵有n个节点的二叉树,每个节点有一个权值,对于一棵子树u,将u的子树中的节点权值从大到小排序,令sz[u]为子树u的大小,

则ans[u] = 1 * a[1] + 2 * a[2] + ... + sz[u] * a[sz[u]],其中a[1] >= a[2] >= ... >= a[u]。求所有节点的答案。

对每个节点建立权值线段树,dfs整棵树,线段树合并

ans[rt] = ans[ls[rt]] + ans[rs[rt]] + size[ls[rt]] * w[rs[rt]],w表示某权值区间的权值和,size表示某权值区间内点的个数。

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;
const int maxn = 1e5 + ;
const int maxnode = 2e6 + ;
struct edge { int to, next; }e[maxn << ];
int head[maxn], ecnt;
void edge_init() { ecnt = ; memset(head, -, sizeof(head)); }
void add(int u, int v) {
e[ecnt].to = v; e[ecnt].next = head[u]; head[u] = ecnt++;
}
int a[maxn], b[maxn];
int root[maxn];
int sz[maxnode], ls[maxnode], rs[maxnode];
long long ans[maxnode], sum[maxnode];
int tot, m; int mergeleaf(int u, int v) {
sz[u] += sz[v];
sum[u] += sum[v];
ans[u] = sum[u] / (long long)sz[u] * (long long) sz[u] * (long long) (sz[u] + 1LL) / 2LL;
return u;
} int merge(int u, int v, int l, int r) {
if (!u || !v) return u | v;
if (l == r) return mergeleaf(u, v);
int mid = (l + r) >> ;
ls[u] = merge(ls[u], ls[v], l, mid);
rs[u] = merge(rs[u], rs[v], mid + , r);
sz[u] = sz[ls[u]] + sz[rs[u]];
sum[u] = sum[ls[u]] + sum[rs[u]];
ans[u] = ans[ls[u]] + ans[rs[u]] + sum[ls[u]] * (long long) sz[rs[u]];
return u;
} void update(int x, int &rt, int l, int r) {
if (!rt) rt = ++tot;
sum[rt] = ans[rt] = (long long) b[x];
sz[rt] = ;
if (l == r) return;
int mid = (l + r) >> ;
if (x <= mid) update(x, ls[rt], l, mid);
else update(x, rs[rt], mid + , r);
} void dfs(int u, int fa) {
update(a[u], root[u], , m);
for (int i = head[u]; i != -; i = e[i].next) {
int v = e[i].to;
if (v == fa) continue;
dfs(v, u);
root[u] = merge(root[u], root[v], , m);
}
} int main() {
int T, n;
scanf("%d", &T);
while (T--) {
edge_init();
scanf("%d", &n);
for (int i = ; i <= n; ++i) scanf("%d", a + i), b[i] = a[i];
sort(b + , b + + n);
m = unique(b + , b + + n) - (b + );
for (int i = ; i <= n; ++i) a[i] = lower_bound(b + , b + + m, a[i]) - b;
for (int u, v ,i = ; i < n; ++i) {
scanf("%d%d", &u, &v);
add(u, v); add(v, u);
}
tot = ;
memset(root, , sizeof(root));
dfs(, );
for (int i = ; i <= n; ++i) printf("%lld ", ans[root[i]]);
puts("");
for (int i = ; i <= tot; ++i) ls[i] = rs[i] = sum[i] = ans[i] = sz[i] = ;
}
}
 

hdu6133 Army Formations 线段树合并的更多相关文章

  1. 2017多校第8场 HDU 6133 Army Formations 线段树合并

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6133 题意:给你一棵n个节点的二叉树,每个节点有一个提交任务的时间,每个节点总的提交任务的罚时为:提交 ...

  2. [XJOI NOI2015模拟题13] C 白黑树 【线段树合并】

    题目链接:XJOI - NOI2015-13 - C 题目分析 使用神奇的线段树合并在 O(nlogn) 的时间复杂度内解决这道题目. 对树上的每个点都建立一棵线段树,key是时间(即第几次操作),动 ...

  3. [BZOJ 2212] [Poi2011] Tree Rotations 【线段树合并】

    题目链接:BZOJ - 2212 题目分析 子树 x 内的逆序对个数为 :x 左子树内的逆序对个数 + x 右子树内的逆序对个数 + 跨越 x 左子树与右子树的逆序对. 左右子树内部的逆序对与是否交换 ...

  4. BZOJ 3307: 雨天的尾巴( LCA + 线段树合并 )

    路径(x, y) +z : u处+z, v处+z, lca(u,v)处-z, fa(lca)处-z, 然后dfs一遍, 用线段树合并. O(M log M + M log N). 复杂度看起来不高, ...

  5. BZOJ2733 [HNOI2012]永无乡 【线段树合并】

    本文版权归ljh2000和博客园共有,欢迎转载,但须保留此声明,并给出原文链接,谢谢合作. 本文作者:ljh2000 作者博客:http://www.cnblogs.com/ljh2000-jump/ ...

  6. bzoj 2243 [SDOI2011]染色(树链剖分+线段树合并)

    [bzoj2243][SDOI2011]染色 2017年10月20日 Description 给定一棵有n个节点的无根树和m个操作,操作有2类: 1.将节点a到节点b路径上所有点都染成颜色c: 2.询 ...

  7. bzoj3702二叉树 线段树合并

    3702: 二叉树 Time Limit: 15 Sec  Memory Limit: 256 MBSubmit: 600  Solved: 272[Submit][Status][Discuss] ...

  8. BZOJ_2212_[Poi2011]Tree Rotations_线段树合并

    BZOJ_2212_[Poi2011]Tree Rotations_线段树合并 Description Byteasar the gardener is growing a rare tree cal ...

  9. B20J_2733_[HNOI2012]永无乡_权值线段树合并

    B20J_2733_[HNOI2012]永无乡_权值线段树合并 Description:n座岛,编号从1到n,每座岛都有自己的独一无二的重要度,按照重要度可以将这n座岛排名,名次用1到 n来表示.某些 ...

随机推荐

  1. python摸爬滚打之day19----类的约束, 异常处理

    1.类的约束 父类对子类某些功能的约束. python 中的两种约束: 1, 提取父类, 然后在父类中定义好方法, 该方法什么都不用干, 就通过主动抛出异常 raise NotImplementedE ...

  2. ES6 字符串

    拓展的方法 子串的识别 ES6 之前判断字符串是否包含子串,用 indexOf 方法,ES6 新增了子串的识别方法. includes():返回布尔值,判断是否找到参数字符串. startsWith( ...

  3. excel将百分比数据转为数值格式

    由于于原给定的数据是百分比格式的, 所以先在excel中将数据格式改为数值 修改步骤: 单纯更改单元格格式为数值没用,先在空白单元格输入数值格式的1,复制该数字,选中要转换格式的数据, 右键 ---- ...

  4. 131A

    #include <stdio.h> #include <string.h> #include <stdbool.h> #define MAXSIZE 105 in ...

  5. 2018-2019-1 20189203《linux内核原理与分析》第六周作业

    第一部分 给Menu OS增加命令 输入命令 rm -rf menu git clone http://github.com/mengning/menu.git make rootfs 查看增加的ti ...

  6. 2018-2019-1 20189203《Linux内核原理与分析》第三周作业

    一.课程学习 计算机的三个法宝:存储程序计算机.函数调用堆栈.中断. 堆栈相关的寄存器:ESP(堆栈指针).EBP(基址指针). 堆栈操作:push:栈顶地址减少4个字节,并将操作数放入栈顶存储单元. ...

  7. 基于容器与微服务架构的Web应用示例eShopOnContainers

    简介 微软官方提供了一个基于Docker和微服务的示例应用eShopOnContainers:它使用了面向服务的架构并且从服务端到客户端都是跨平台的:该架构使用通过http作为客户端与服务端直接的通信 ...

  8. smartctl 检测磁盘信息

    smartctl  -i 指定设备 -d 指定设备类型,例如:ata, scsi, marvell, sat, 3ware,N -a 或A 显示所有信息 -l 指定日志的类型,例如:TYPE: err ...

  9. [macOS] keychain的跳坑之旅!git拉取的权限问题

    故事背景,svn与git各有长处,不过git大势所趋吧,那就搞搞.git的服务端,是基于phabricator搭建的,关于它的资料自行google就好了.其实之前运维已经搭好了phabricator了 ...

  10. Linux基础命令---lprm删除打印任务

    lprm lprm指令用来删除当前打印队列上的任务,如果没有指定,那么就删除当前打印任务.您可以指定一个或多个职务ID编号来取消这些职务,或者使用选项”-”取消所有作业. 此命令的适用范围:RedHa ...