题意:给你一颗树,每个节点有有一个权值,每次询问从x到y的最短路上权值在c到d之间的所有的点的权值和是多少。

思路:肯定要用树剖,因为询问c到d之间这种操作树上倍增很难做,但是用其它数据结构可以比较好的查询。我们可以用线段树来进行这种操作。每次询问一个区间时,如果当前区间被查询区间完全覆盖,并且区间里的最大指小于等于d,最小值大于等于c,才返回,否则继续查询。这种做法其实可以被卡掉,比如很长的路径上点权都是1, 2, 1, 2这种,而询问的c和d都是1,这样线段树上的询问会被卡成O(n)的。我感觉比较可行的做法是离散化之后用主席树,这样可以保证O(logn),但是既然没卡这个,就懒得写这种做法了。

线段树做法:

#include <bits/stdc++.h>
#define LL long long
#define ls(x) (x << 1)
#define rs(x) ((x << 1) | 1)
using namespace std;
const int maxn = 100010;
int head[maxn], Next[maxn * 2], ver[maxn * 2];
int son[maxn], d[maxn], f[maxn], top[maxn], sz[maxn], dfn[maxn];
int n, m, tot, cnt;
int a[maxn], b[maxn];
void add(int x, int y) {ver[++tot] = y;Next[tot] = head[x];head[x] = tot;
}
struct SegmentTree {int mx, mi;LL sum;
};
SegmentTree tr[maxn * 4];
void pushup(int o) {tr[o].sum = tr[ls(o)].sum + tr[rs(o)].sum;tr[o].mi = min(tr[ls(o)].mi, tr[rs(o)].mi);tr[o].mx = max(tr[ls(o)].mx, tr[rs(o)].mx);
}
void build(int o, int l, int r) {if(l == r) {tr[o].mx = tr[o].mi = tr[o].sum = a[l];return;}int mid = (l + r) >> 1;build(ls(o), l, mid);build(rs(o), mid + 1, r);pushup(o);
}
bool match(int o, int l, int r) {return tr[o].mi >= l && tr[o].mx <= r;
}
LL query(int o, int l, int r, int ql, int qr, int lb, int rb) {if(l >= ql && r <= qr && match(o, lb, rb)) {return tr[o].sum;}int mid = (l + r) >> 1;LL ans = 0;if(ql <= mid && !(tr[ls(o)].mx < lb || tr[ls(o)].mi > rb)) ans += query(ls(o), l, mid, ql, qr, lb, rb);if(qr > mid && !(tr[rs(o)].mx < lb || tr[rs(o)].mi > rb)) ans += query(rs(o), mid + 1, r, ql, qr, lb, rb);return ans;
}
void dfs1(int x, int fa) {sz[x] = 1;f[x] = fa;d[x] = d[fa] + 1;for (int i = head[x]; i; i = Next[i]) {int y = ver[i];if(y == fa) continue;dfs1(y, x);sz[x] += sz[y];if(!son[x] || sz[y] > sz[son[x]])son[x] = y;}
}
void dfs2(int x, int fa, int t) {top[x] = t;dfn[x] = ++cnt;a[dfn[x]] = b[x];if(son[x]) dfs2(son[x], x, t);for (int i = head[x]; i; i = Next[i]) {int y = ver[i];if(y == fa || y == son[x]) continue;dfs2(y, x, y);}
}
LL solve(int l, int r, int x, int y) {LL ans = 0;while(top[l] != top[r]) {if(d[top[l]] > d[top[r]]) {ans += query(1, 1, n, dfn[top[l]], dfn[l], x, y);l = f[top[l]]; } else {ans += query(1, 1, n, dfn[top[r]], dfn[r], x, y);r = f[top[r]];}}if(d[l] < d[r]) ans += query(1, 1, n, dfn[l], dfn[r], x, y);else ans += query(1, 1, n, dfn[r], dfn[l], x, y);return ans;
}
int main() {int x, y, l, r;while(~scanf("%d%d", &n, &m)) {memset(head, 0, sizeof(head));memset(son, 0, sizeof(son));memset(f, 0, sizeof(f));memset(sz, 0, sizeof(sz));memset(top, 0, sizeof(top));memset(d, 0, sizeof(d));tot = 0;cnt = 0;for (int i = 1; i <= n; i++)scanf("%d", &b[i]);for (int i = 1; i <= n - 1; i++) {scanf("%d%d", &x, &y);add(x, y);add(y, x);}dfs1(1, 0);dfs2(1, 0, 1);build(1, 1, n);while(m--) {scanf("%d%d%d%d", &l, &r, &x, &y);cout << solve(l, r, x, y);if(m == 0) cout << endl;else cout << " ";}}
}

  

转载于:https://www.cnblogs.com/pkgunboat/p/10651445.html

HDU 6162 树链剖分相关推荐

  1. hdu 3966(树链剖分+线段树区间更新)

    传送门:Problem 3966 https://www.cnblogs.com/violet-acmer/p/9711441.html 学习资料: [1]线段树区间更新:https://blog.c ...

  2. hdu 3966( 树链剖分+点权更新)

    题意:给一棵树,并给定各个点权的值,然后有3种操作: I C1 C2 K: 把C1与C2的路径上的所有点权值加上K D C1 C2 K:把C1与C2的路径上的所有点权值减去K Q C:查询节点编号为C ...

  3. hdu 5274(树链剖分)

    解题思路:这道题据说是树链剖分,所以也学习了一下. http://blog.sina.com.cn/s/blog_7a1746820100wp67.html 不同的是这里是点权值,我按照相似的处理方式 ...

  4. HDU 3966 树链剖分后线段树维护

    题意: 一棵树, 操作1.$path(a,b)$之间的点权$+k$ 操作2.单点查询 题解: 树链剖分即可,注意代码细节,双向映射 主要是记录一下板子 #include <string.h> ...

  5. HDU 5405 (树链剖分+线段树)

    Problem Sometimes Naive 题目大意 给你一棵n个节点的树,有点权. 要求支持两种操作: 操作1:更改某个节点的权值. 操作2:给定u,v, 求 Σw[i][j]   i , j ...

  6. hdu 5052 树链剖分+线段树+区间合并

    各种裸,但合在一起好恶心... 因为路径是有向的,所以要维护区间里向两个方向走的最大收益和区间里的最大最小值,要用到区间合并的线段树 #include <iostream> #includ ...

  7. HDU 6162 2017 多校训练:Ch's gift(树链剖分)

    题意: 有一棵n个节点的树,m次查询,每次查询x, y, a, b表示节点x到y的路径上所有在[a, b]范围内的权值和 树链剖分+线段树 询问离线,按a和b分别排序求出所有小于a和所有小于b+1的权 ...

  8. HDU 5274 Dylans loves tree(树链剖分)

    [题目链接] http://acm.hdu.edu.cn/showproblem.php?pid=5274 [题目大意] 给出一棵树,每个点有一个权值,权值可修改,且大于等于0,询问链上出现次数为奇数 ...

  9. HDU - 3966 Aragorn's Story(树链剖分)

    题目传送门:HDU - 3966 Aragorn's Story 题目大意: 存在一个树,树上每个节点为一个阵营,阵营中存在敌人,现在要进行以下操作 I  C1  C2  K :将阵营C1到阵营C2路 ...

  10. HDU 2460 Network(双连通+树链剖分+线段树)

    HDU 2460 Network 题目链接 题意:给定一个无向图,问每次增加一条边,问个图中还剩多少桥 思路:先双连通缩点,然后形成一棵树,每次增加一条边,相当于询问这两点路径上有多少条边,这个用树链 ...

最新文章

  1. 贝叶斯分类器的matlab实现_贝叶斯实验
  2. 面试官:前端跨页面通信,你知道哪些方法?
  3. java list 转数组_数组转List,一定要小心这个坑!
  4. 怎么看电脑系统是win几_一文看懂arm架构和x86架构有什么区别
  5. Android之运行Java.lang.UnsatisfiedLinkError的错误解决办法
  6. mysql所支持的比较运算符_mysql比较运算符有哪些?Mysql比较运算符详解
  7. java jpeg压缩解码_JPEG图像压缩原理简介
  8. 计算机英语 考研 翻译,研究生英语翻译笔记
  9. 深度学习自学(二十五):目标跟踪
  10. 【风马一族_php】
  11. 穿上钢铁侠战衣变身钢铁侠,现代表示我做到了!
  12. python爬虫论文参考文献格式_Python爬虫进阶必备 | XX文学加密分析实例
  13. vue中动态获取dom元素进行操作
  14. Maya2019 XGen的Utility面板内容为空
  15. CF1619B Squares and Cubes
  16. 【甄选靶场】Vulnhub百个项目渗透——项目五十二:Fowsniff-1(任务挟持)
  17. 圆形比例图(饼状图)
  18. 开源开放 生态共建 | openKylin社区单位会员突破200家!
  19. stdlib.h和stdio.h有什么区别
  20. hnc8进linux环境,鸟哥的linux私房菜(基础篇,8、开机关机、在线)命令

热门文章

  1. python中特殊符号怎么输入_python中怎么输入引号
  2. linux查看php执行用户,在浏览器中打开php文件时,是Linux中的哪个用户执行的?...
  3. 【Java程序设计】数学函数
  4. Hive 求top N
  5. flink 入门及安装
  6. Windows核心编程_更改当前工作目录
  7. 使用Opencv将RGB颜色空间转换到HSV颜色空间/灰度图
  8. Dos命令批量操作复制出26个虚拟盘空间
  9. 关于区块链通证模型,你想知道的都在这
  10. SQLserver nText和varchar 不兼容