hdu6162(树链剖分)
hdu6162
题意
给出一颗带点权的树,每次询问一对节点 \((u, v)\),问 \(u\) 到 \(v\) 的最短路径上所有节点权值在 \([c1, c2]\) 区间内的和。
分析
树链剖分,那么我们只需要处理一个区间内节点权值在 \([c1, c2]\) 之间的和。建一颗线段树,每个节点维护当前区间内所有的点已经排序后的权值,以及前缀和。那么两次二分,前缀和相减就可以快速得到区间内权值在 \([c1, c2]\) 的所有节点的和。
code
#include<bits/stdc++.h>
#define lson l, m, rt << 1
#define rson m + 1, r, rt << 1 | 1
using namespace std;
typedef long long ll;
const int MAXN = 1e5 + 10;
int n, m;
int fa[MAXN]; // fa[v]: v 的父亲
int dep[MAXN]; // dep[v]: v 的深度(根深度为1)
int siz[MAXN]; // : 以 v 为根的子树的节点数
int son[MAXN]; // : 重儿子,siz[u] 为 v 的子节点中 siz 值最大的,那么 u 就是 v 的重儿子
int top[MAXN]; // : 表示 v 所在的重链的顶端节点
int w[MAXN]; // : 表示 v 在线段树中的位置
int num; // 将树映射到线段树上的标号
int cnt, head[MAXN << 1];
struct Edge {
int to, next;
}edge[MAXN << 1];
void addedge(int u, int v) {
edge[cnt].to = v;
edge[cnt].next = head[u];
head[u] = cnt++;
}
int tre[MAXN]; // 线段树上的点在树上的节点编号
int cost[MAXN];
void dfs(int u) {
siz[u] = 1; son[u] = 0;
for(int i = head[u]; ~i; i = edge[i].next) {
if(edge[i].to != fa[u]) {
fa[edge[i].to] = u;
dep[edge[i].to] = dep[u] + 1;
dfs(edge[i].to);
if(siz[edge[i].to] > siz[son[u]]) son[u] = edge[i].to;
siz[u] += siz[edge[i].to];
}
}
}
void build_tree(int u, int tp) {
w[u] = ++num; top[u] = tp;
if(son[u]) build_tree(son[u], top[u]); // 使重链各边在线段树中呈连续分布
for(int i = head[u]; ~i; i = edge[i].next) {
int v = edge[i].to;
if(v != son[u] && v != fa[u])
build_tree(v, v);
}
}
vector<int> v[MAXN << 2];
vector<ll> sum[MAXN << 2];
void pushUp(int rt) {
v[rt].resize(v[rt << 1].size() + v[rt << 1 | 1].size());
merge(v[rt << 1].begin(), v[rt << 1].end(), v[rt << 1 | 1].begin(), v[rt << 1 | 1].end(), v[rt].begin());
sort(v[rt].begin(), v[rt].end());
ll s = 0;
for(int i = 0; i < v[rt].size(); i++) {
s += v[rt][i];
sum[rt].push_back(s);
}
}
void build(int l, int r, int rt) {
v[rt].clear();
sum[rt].clear();
if(l == r) {
v[rt].push_back(cost[tre[l]]);
sum[rt].push_back(cost[tre[l]]);
return;
}
int m = (l + r) / 2;
build(lson);
build(rson);
pushUp(rt);
}
ll query(int L, int R, int c1, int c2, int l, int r, int rt) {
if(L <= l && R >= r) {
int posr = upper_bound(v[rt].begin(), v[rt].end(), c2) - v[rt].begin(); posr--;
int posl = lower_bound(v[rt].begin(), v[rt].end(), c1) - v[rt].begin(); posl--;
ll x = posr < 0 ? 0 : sum[rt][posr];
ll y = posl < 0 ? 0 : sum[rt][posl];
return x - y;
}
int m = (l + r) / 2;
ll res = 0;
if(m >= L) res += query(L, R, c1, c2, lson);
if(m < R) res += query(L, R, c1, c2, rson);
return res;
}
ll seek(int v, int u, int c1, int c2) {
int t1 = top[v], t2 = top[u];
ll res = 0;
while(t1 != t2) {
if(dep[t1] < dep[t2]) {
swap(t1, t2); swap(v, u);
}
res += query(w[t1], w[v], c1, c2, 1, n, 1);
v = fa[t1]; t1 = top[v];
}
if(dep[v] > dep[u]) swap(v, u);
return res + query(w[v], w[u], c1, c2, 1, n, 1);
}
//适用于正整数
template <class T>
inline void scan_d(T &ret) {
char c; ret=0;
while((c=getchar())<'0'||c>'9');
while(c>='0'&&c<='9') ret=ret*10+(c-'0'),c=getchar();
}
int main() {
while(~scanf("%d%d", &n, &m)) {
memset(head, -1, sizeof head);
cnt = num = 0;
for(int i = 1; i <= n; i++) {
scanf("%d", &cost[i]);
}
for(int i = 0; i < n - 1; i++) {
int u, v;
scanf("%d%d", &u, &v);
addedge(u, v);
addedge(v, u);
}
dfs(1);
build_tree(1, 1);
for(int i = 1; i <= n; i++) {
tre[w[i]] = i;
}
build(1, n, 1);
for(int i = 0; i < m; i++) {
int l, r, c1, c2;
scan_d(l); scan_d(r); scan_d(c1); scan_d(c2);
printf("%lld%c", seek(l, r, c1, c2), " \n"[i == m - 1]);
}
}
return 0;
}
hdu6162(树链剖分)的更多相关文章
- BZOJ 3626: [LNOI2014]LCA [树链剖分 离线|主席树]
3626: [LNOI2014]LCA Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 2050 Solved: 817[Submit][Status ...
- BZOJ 1984: 月下“毛景树” [树链剖分 边权]
1984: 月下“毛景树” Time Limit: 20 Sec Memory Limit: 64 MBSubmit: 1728 Solved: 531[Submit][Status][Discu ...
- codevs 1228 苹果树 树链剖分讲解
题目:codevs 1228 苹果树 链接:http://codevs.cn/problem/1228/ 看了这么多树链剖分的解释,几个小时后总算把树链剖分弄懂了. 树链剖分的功能:快速修改,查询树上 ...
- 并查集+树链剖分+线段树 HDOJ 5458 Stability(稳定性)
题目链接 题意: 有n个点m条边的无向图,有环还有重边,a到b的稳定性的定义是有多少条边,单独删去会使a和b不连通.有两种操作: 1. 删去a到b的一条边 2. 询问a到b的稳定性 思路: 首先删边考 ...
- 树链剖分+线段树 CF 593D Happy Tree Party(快乐树聚会)
题目链接 题意: 有n个点的一棵树,两种操作: 1. a到b的路径上,给一个y,对于路径上每一条边,进行操作,问最后的y: 2. 修改某个条边p的值为c 思路: 链上操作的问题,想树链剖分和LCT,对 ...
- 树链剖分+线段树 HDOJ 4897 Little Devil I(小恶魔)
题目链接 题意: 给定一棵树,每条边有黑白两种颜色,初始都是白色,现在有三种操作: 1 u v:u到v路径(最短)上的边都取成相反的颜色 2 u v:u到v路径上相邻的边都取成相反的颜色(相邻即仅有一 ...
- bzoj2243树链剖分+染色段数
终于做了一道不是一眼出思路的代码题(⊙o⊙) 之前没有接触过这种关于染色段数的题目(其实上课好像讲过),于是百度了一下(现在思维能力好弱) 实际上每一段有用的信息就是总共有几段和两段各是什么颜色,在开 ...
- bzoj3631树链剖分
虽然是水题1A的感觉太爽了O(∩_∩)O~ 题意相当于n-1次树上路径上每个点权值+1,最后问每个点的权值 本来想写线段树,写好了change打算框架打完了再来补,结果打完发现只是区间加和单点查 前缀 ...
- BZOJ 3531: [Sdoi2014]旅行 [树链剖分]
3531: [Sdoi2014]旅行 Time Limit: 20 Sec Memory Limit: 512 MBSubmit: 1685 Solved: 751[Submit][Status] ...
随机推荐
- 安装全局webpack
npm ls webpack 和npm ls webpack -g 查看本地和全局版本 npm install webpack@1.15.0 -g 全局 然后到项目里面 npm install npm ...
- Android逆向之旅---静态方式分析破解视频编辑应用「Vue」水印问题
一.故事背景 现在很多人都喜欢玩文艺,特别是我身边的UI们,拍照一分钟修图半小时.就是为了能够在朋友圈显得逼格高,不过的确是挺好看的,修图的软件太多了就不多说了,而且一般都没有水印啥的.相比较短视频有 ...
- poj3133 Manhattan Wiring
Manhattan Wiring Time Limit: 5000MS Memory Limit: 65536K Total Submissions: 2016 Accepted: 1162 ...
- bzoj2424 [HAOI2010]订货 dp+单调性
[HAOI2010]订货 Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 1311 Solved: 884[Submit][Status][Discu ...
- CSS3学习笔记之立体线框球形动画
效果截图: HTML代码: <div class="ball-box"> <div class="ball"> <div clas ...
- 慕课网javascript 进阶篇 第九章 编程练习
把平常撸的码来博客上再撸一遍既可以加深理解,又可以理清思维.还是很纯很纯的小白,各位看官老爷们,不要嫌弃.最近都是晚睡,昨晚也不例外,两点多睡的.故,八点起来的人不是很舒服,脑袋有点晕呼呼,鉴于昨晚看 ...
- Android百度定位地图使用--文章集锦
Android百度定位API使用方法 Android百度地图开发(一)之初体验 AndroidNote013.在百度地图上画出轨迹 Android学习笔记之百度地图(分条目覆盖物:ItemizedOv ...
- 状压dp的题目列表 (一)
状压dp的典型的例子就是其中某个数值较小. 但是某个数值较小也不一定是状压dp,需要另外区分的一种题目就是用暴力解决的题目,例如UVA818 紫书215 题目列表: ①校长的烦恼 UVA10817 紫 ...
- Mysql TEXT类型长度
BLOBTEXT一个BLOB或TEXT列,最大长度为65535(2^16-1)个字符. MEDIUMBLOBMEDIUMTEXT一个BLOB或TEXT列,最大长度为16777215(2^24-1)个字 ...
- Ring0层创建事件,Ring3层接收
在学习驱动过程中,一个很重要的内容就是Ring3层与Ring0层的通信,方法有很多种,互斥体,信号量,文件等等,用的比较普遍的,还是事件.所以在学习的过程中,做了一个简单的Demo,主要是体会一下方法 ...