HDU 6162 树链剖分
题意:给你一颗树,每个节点有有一个权值,每次询问从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 << " ";
}
}
}
HDU 6162 树链剖分的更多相关文章
- hdu 5893 (树链剖分+合并)
List wants to travel Time Limit: 6000/3000 MS (Java/Others) Memory Limit: 131072/131072 K (Java/O ...
- hdu 5052 树链剖分
Yaoge’s maximum profit Time Limit: 10000/5000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/ ...
- hdu 4897 树链剖分(重轻链)
Little Devil I Time Limit: 16000/8000 MS (Java/Others) Memory Limit: 131072/131072 K (Java/Others ...
- hdu 5274 树链剖分
Dylans loves tree Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 131072/131072 K (Java/Othe ...
- HDU 3966 (树链剖分+线段树)
Problem Aragorn's Story (HDU 3966) 题目大意 给定一颗树,有点权. 要求支持两种操作,将一条路径上的所有点权值增加或减少ai,询问某点的权值. 解题分析 树链剖分模板 ...
- hdu 3966(树链剖分+线段树区间更新)
传送门:Problem 3966 https://www.cnblogs.com/violet-acmer/p/9711441.html 学习资料: [1]线段树区间更新:https://blog.c ...
- HDU 3966 /// 树链剖分+树状数组
题意: http://acm.hdu.edu.cn/showproblem.php?pid=3966 给一棵树,并给定各个点权的值,然后有3种操作: I x y z : 把x到y的路径上的所有点权值加 ...
- hdu 4729 树链剖分
思路:这个树链剖分其实还是比较明显的.将边按权值排序后插入线段树,然后用线段树查找区间中比某个数小的数和,以及这样的数的个数.当A<=B时,就全部建新的管子. 对于A>B的情况比较 建一条 ...
- hdu 3966 树链剖分
思路:树链剖分入门题,我这门入得好苦啊,程序很快写出来了,可是在LCA过程中把update函数里的左右边界位置写反了,一直RE到死. #pragma comment(linker, "/ST ...
随机推荐
- os.path.abspath()的作用
语法 os.path.abspath(path) 作用 返回绝对路径 实例 import os print(os.path.abspath(".")) #当前目录的绝对路径 pri ...
- Kestrel Web 服务器学习笔记
前言: ASP.NET Core 已经不是啥新鲜的东西,很多新启的项目都会首选 Core 做开发: 而 Kestrel 可以说是微软推出的唯一真正实现跨平台的 Web 服务器了: Kestrel 利用 ...
- 剑指offer--18.从尾到头打印链表
递归,逐个加到后面 ------------------------------------------------------------------------------ 时间限制:1秒 空间限 ...
- Android Volley完全解析(四),带你从源码的角度理解Volley
转载请注明出处:http://blog.csdn.net/guolin_blog/article/details/17656437 经过前三篇文章的学习,Volley的用法我们已经掌握的差不多了,但是 ...
- Zijian-lv #3 树句节狗提
如你所见,这是一道狗题 一棵树,多次询问与一个点距离至少为 $k$ 的点的权值和 $n,q \leq 2525010$ sol: 长链剖分 需要注意的是这道题卡空间 我把我所有的 vector 换成链 ...
- java中List、Map、Set、Collection、Stack、Queue等的使用
java中这几个东西是比较常用的,虽然我用的不多,也正是因为用的不多,所以我一直搞不清楚他们之间的具体用法以及相互之间的关系,现在特单独作为一个东西来总结一下. 本文参考一下资料: 1.<jav ...
- U盘操作
一.8G的U盘被设置为2G,如何恢复 1.下载usboot 1.7 打开以后,选中U盘,点击[点击此处选择工作模式],选择[用0重置参数] ,然后点[开始].2.完成后它会提示拔下U盘,此时拔下U盘, ...
- Linux内核 - 定时器
#include <linux/timer.h> //头文件 struct timer_list mytimer; //定义变量 static void my_timer(unsigned ...
- Day2-VIM(四):修改
字符替换 r 单个字符替换 R 连续替换 - 更改大小写 很简单,多试试就行了 tips:4-更改连续4个字符的大小写,很有意思 单词修改 cw 从光标处修改到单词结尾 cb 从光标处修改到单词开头 ...
- Day1--Python基础1--下半部分
一..pyc是什么 1. Python是一门解释型语言? 我初学Python时,听到的关于Python的第一句话就是,Python是一门解释性语言,我就这样一直相信下去,直到发现了*.pyc文件的存在 ...