HDU - 3966 树链刨分
操作就是询问某个点的值, 然后就是对一条路径上的值全部修改。
最基本的树刨题目了。
树刨的思想:
1. 对于每个点找到他的重儿子。
void dfs1(int o, int u){
sz[u] = ;
for(int i = head[u]; ~i; i = nt[i]){
int v = to[i];
if(v == o) continue;
dfs1(u, v);
if(sz[v] > sz[son[u]]) son[u] = v;
sz[u] += sz[v];
}
}
2.求DFS序。对于每个节点记录下dfs序,他的父节点,他的祖先节点(也就是这条重链上最高的节点),这个点对应线段树的位置,线段树对应到节点的位置。
在DFS的过程中,先搜重儿子,然后再搜轻儿子,这样可以保证一条重链在线段树中是连续的,故可以用线段树区间修改。
void dfs2(int o, int u, int t){
deep[u] = deep[o] + ;
top[u] = t;
fa[u] = o;
dfn[u] = ++dtot;
dto[dtot] = u;
if(son[u]) dfs2(u, son[u], t);
for(int i = head[u]; ~i; i = nt[i]){
int v = to[i];
if(v == o || v == son[u]) continue;
dfs2(u, v, v);
}
}
3. 接下来就是对路径的修改。
假如我们需要修改 u -- v 这条路径。
那么我们先令fu = top[u], fv = top[v], 如果不相等,则将深度大的往上跳,跳的时候完成你要的操作。
相等之后就说明在一条链上了, 这个时候完成操作后就可以退出了。
注意的是, 判断的是 fu 和 fv 的深度 而不是 u v 的深度。
void Updata_Path(int x, int y, int c){
int fx = top[x], fy = top[y];
while(fx != fy){
if(deep[fx] > deep[fy]){
Updata(dfn[fx],dfn[x],c,,n,);
x = fa[fx]; fx = top[x];
}
else {
Updata(dfn[fy],dfn[y],c,,n,);
y = fa[fy]; fy = top[y];
}
}
if(deep[x] < deep[y]) Updata(dfn[x], dfn[y], c, , n, );
else Updata(dfn[y], dfn[x], c, , n,);
}
代码:
/*
code by: zstu wxk
time: 2019/02/22
*/
#include<bits/stdc++.h>
using namespace std;
#define Fopen freopen("_in.txt","r",stdin); freopen("_out.txt","w",stdout);
#define LL long long
#define ULL unsigned LL
#define fi first
#define se second
#define pb push_back
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define lch(x) tr[x].son[0]
#define rch(x) tr[x].son[1]
#define max3(a,b,c) max(a,max(b,c))
#define min3(a,b,c) min(a,min(b,c))
typedef pair<int,int> pll;
const int inf = 0x3f3f3f3f;
const int _inf = 0xc0c0c0c0;
const LL INF = 0x3f3f3f3f3f3f3f3f;
const LL _INF = 0xc0c0c0c0c0c0c0c0;
const LL mod = (int)1e9+;
const int N = 2e5 + ;
int n, m, p;
int tr[N<<], lz[N<<], a[N];
int head[N], nt[N], to[N], tot;
int sz[N], son[N];
int top[N], fa[N], dfn[N], dto[N], deep[N], dtot;
void Build(int l, int r, int rt){
lz[rt] = tr[rt] = ;
if(l == r){
tr[rt] = a[dto[l]];
return ;
}
int m = l+r >> ;
Build(lson); Build(rson);
return ;
}
void PushDown(int rt){
if(lz[rt]){
lz[rt<<] += lz[rt];
lz[rt<<|] += lz[rt];
tr[rt<<] += lz[rt];
tr[rt<<|] += lz[rt];
lz[rt] = ;
}
return ;
}
void add(int u, int v){
to[tot] = v;
nt[tot] = head[u];
head[u] = tot++;
}
void dfs1(int o, int u){
sz[u] = ;
for(int i = head[u]; ~i; i = nt[i]){
int v = to[i];
if(v == o) continue;
dfs1(u, v);
if(sz[v] > sz[son[u]]) son[u] = v;
sz[u] += sz[v];
}
}
void dfs2(int o, int u, int t){
deep[u] = deep[o] + ;
top[u] = t;
fa[u] = o;
dfn[u] = ++dtot;
dto[dtot] = u;
if(son[u]) dfs2(u, son[u], t);
for(int i = head[u]; ~i; i = nt[i]){
int v = to[i];
if(v == o || v == son[u]) continue;
dfs2(u, v, v);
}
}
int Query(int x, int l, int r, int rt){
if(l == r)
return tr[rt];
int m = l+r >> ;
PushDown(rt);
if(x <= m) return Query(x, lson);
return Query(x, rson);
}
void Updata(int L, int R, int C, int l, int r, int rt){
// cout << L << " l with r " << r << endl;
if(L <= l && r <= R){
lz[rt] += C;
tr[rt] += C;
return ;
}
int m = l+r >> ;
PushDown(rt);
if(L <= m) Updata(L, R, C, lson);
if(m < R) Updata(L, R, C, rson);
return ;
}
void Updata_Path(int x, int y, int c){
int fx = top[x], fy = top[y];
while(fx != fy){
if(deep[fx] > deep[fy]){
Updata(dfn[fx],dfn[x],c,,n,);
x = fa[fx]; fx = top[x];
}
else {
Updata(dfn[fy],dfn[y],c,,n,);
y = fa[fy]; fy = top[y];
}
}
if(deep[x] < deep[y]) Updata(dfn[x], dfn[y], c, , n, );
else Updata(dfn[y], dfn[x], c, , n,);
}
void init(){
memset(head, -, sizeof(head));
memset(son, , sizeof son);
tot = dtot = ;
}
void Ac(){
for(int i = ; i <= n; ++i) scanf("%d", &a[i]);
for(int i = ,u,v; i < n; ++i){
scanf("%d%d", &u, &v);
add(u, v); add(v, u);
}
dfs1(,);
dfs2(,,);
Build(,n,);
char op[];
int x, y, c;
for(int i = ; i <= p; ++i){
scanf("%s", op);
if(op[] == 'Q') {
scanf("%d", &x);
printf("%d\n", Query(dfn[x], , n, ));
}
else {
scanf("%d%d%d", &x, &y, &c);
if(op[] == 'D') c = -c;
Updata_Path(x,y,c);
// Tdfs(1,n,1);
}
}
}
int main(){
while(~scanf("%d%d%d", &n, &m, &p)){
init();
Ac();
}
return ;
}
/*
3 2 5
1 2 3
2 1
1 3
I 2 3 5
Q 2 7 6 10
0 0 0 0 0 0 0
1 2
2 3
3 4
1 5
5 6
I 4 6 1
Q 1 */
HDU - 3966 树链刨分的更多相关文章
- hdu 5452(树链刨分)
看到题目,想了挺长时间,发现不会,然后看着样子像是树上成段操作,所以查了下树链刨分,结果真的就是这个东西... Minimum Cut Time Limit: 3000/2000 MS (Java/O ...
- bzoj 5210(树链刨分下做个dp)
5210: 最大连通子块和 Time Limit: 20 Sec Memory Limit: 128 MBSubmit: 211 Solved: 65[Submit][Status][Discus ...
- xcoj 1103 插线板(树链刨分求最大子段和)
1103: 插线板 时间限制: 1 Sec 内存限制: 128 MB提交: 14 解决: 7 标签提交统计讨论版EditTestData 题目描述 从前有一堆古老的插线板,任意两个插线板之间只有一 ...
- 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 ...
- 树链刨分(class版)
class版树链剖(刨)分 感谢沙华大佬的赞助 其实没什么太大变化,就是用了几次一顿乱指... CODE: #include<iostream> #include<cstdio> ...
- HDU 3966 /// 树链剖分+树状数组
题意: http://acm.hdu.edu.cn/showproblem.php?pid=3966 给一棵树,并给定各个点权的值,然后有3种操作: I x y z : 把x到y的路径上的所有点权值加 ...
- hdu 3966 树链剖分
思路:树链剖分入门题,我这门入得好苦啊,程序很快写出来了,可是在LCA过程中把update函数里的左右边界位置写反了,一直RE到死. #pragma comment(linker, "/ST ...
- HDU 3966 树链剖分后线段树维护
题意: 一棵树, 操作1.$path(a,b)$之间的点权$+k$ 操作2.单点查询 题解: 树链剖分即可,注意代码细节,双向映射 主要是记录一下板子 #include <string.h> ...
随机推荐
- HashMap常见面试题整理
花了三天时间来仔细阅读hashMap的源码,期间补了下不少数据结构的知识,刷了不少相关的面试题并进行了整理 1.谈一下HashMap的特性? 1.HashMap存储键值对实现快速存取,允许为null. ...
- 安装MySQL5.7 安装环境:CentOS7 64位 MINI版,
安装环境:CentOS7 64位 MINI版,安装MySQL5.7 1.配置YUM源 在MySQL官网中下载YUM源rpm安装包:http://dev.mysql.com/downloads/repo ...
- 【Java例题】7.5 文件题2-学生成绩统计
5.学生成绩统计.已有一个学生成绩文件,含有多位学生的各三门课的成绩:读取这个文件中的每位学生的三门课成绩,然后计算均分:最后对这些均分按照大于或小于75分的界限,分别写到另两个文件中. packag ...
- 【Java例题】2.2 分数类
2.定义分数类,包括分子和分母变量.构造方法. 加减乘除方法.化简方法.值计算方法和显示分子和分母的方法. 然后编写一个主类,在其主方法中通过定义两个分数对象来 显示每一个分数的分子值.分母值.化简和 ...
- 数据结构之最小堆的实现C++版
完全二叉树之所以用数组的方式存在,在于他的一个特性 若子节点为i,则父节点为(i-1)/2,注意c++特性,该结果肯定是个整数. 若父节点为j,则子节点必为2*j+1;则在数组里面可以非常方便的通过下 ...
- 学习Qt的一点小感想
作为一名电子信息工程的学生,嵌入式似乎是不二的选择,然后我便学习了一下在嵌入式广泛应用的QT软件,刚开始就是学学控件,觉得还是简单,也觉得比较新颖,可是到了做一些具体的小东西就会发现学的东西远远不够, ...
- mybatis学习笔记(二)
三种查询方式,由<resultType 属性控制> 第一种 selectList() 返回值为LIst List<People> selectList = session.se ...
- java并发编程(十七)----(线程池)java线程池架构和原理
前面我们简单介绍了线程池的使用,但是对于其如何运行我们还不清楚,Executors为我们提供了简单的线程工厂类,但是我们知道ThreadPoolExecutor是线程池的具体实现类.我们先从他开始分析 ...
- 简单设计企业级JOB平台
前言 在企业级项目中有许多能够用到定时任务的场景例如: 在某个时间点统一给某些用户发送邮件信息 接口表数据发送 某月某日更新报表数据 ...... 目前我们使用SpringBoot快速整合Quartz ...
- Spring 2017 Assignments2
一.作业要求 原版:http://cs231n.github.io/assignments2017/assignment2/ 翻译:http://www.mooc.ai/course/268/lear ...