题目传送门

操作就是询问某个点的值, 然后就是对一条路径上的值全部修改。

最基本的树刨题目了。

树刨的思想:

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 树链刨分的更多相关文章

  1. hdu 5452(树链刨分)

    看到题目,想了挺长时间,发现不会,然后看着样子像是树上成段操作,所以查了下树链刨分,结果真的就是这个东西... Minimum Cut Time Limit: 3000/2000 MS (Java/O ...

  2. bzoj 5210(树链刨分下做个dp)

    5210: 最大连通子块和 Time Limit: 20 Sec  Memory Limit: 128 MBSubmit: 211  Solved: 65[Submit][Status][Discus ...

  3. xcoj 1103 插线板(树链刨分求最大子段和)

    1103: 插线板 时间限制: 1 Sec  内存限制: 128 MB提交: 14  解决: 7 标签提交统计讨论版EditTestData 题目描述 从前有一堆古老的插线板,任意两个插线板之间只有一 ...

  4. HDU 3966 (树链剖分+线段树)

    Problem Aragorn's Story (HDU 3966) 题目大意 给定一颗树,有点权. 要求支持两种操作,将一条路径上的所有点权值增加或减少ai,询问某点的权值. 解题分析 树链剖分模板 ...

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

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

  6. 树链刨分(class版)

    class版树链剖(刨)分 感谢沙华大佬的赞助 其实没什么太大变化,就是用了几次一顿乱指... CODE: #include<iostream> #include<cstdio> ...

  7. HDU 3966 /// 树链剖分+树状数组

    题意: http://acm.hdu.edu.cn/showproblem.php?pid=3966 给一棵树,并给定各个点权的值,然后有3种操作: I x y z : 把x到y的路径上的所有点权值加 ...

  8. hdu 3966 树链剖分

    思路:树链剖分入门题,我这门入得好苦啊,程序很快写出来了,可是在LCA过程中把update函数里的左右边界位置写反了,一直RE到死. #pragma comment(linker, "/ST ...

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

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

随机推荐

  1. JavaScript数据结构——集合的实现与应用

    与数学中的集合概念类似,集合由一组无序的元素组成,且集合中的每个元素都是唯一存在的.可以回顾一下中学数学中集合的概念,我们这里所要定义的集合也具有空集(即集合的内容为空).交集.并集.差集.子集的特性 ...

  2. ubuntu18.04下安装matlab2018a

    一.下载 百度网盘链接:https://pan.baidu.com/s/1M6KafnsljmYV9_5m_1pXMw 提取玛:jp76 二.安装 下载下来的文件夹中有三个文件,分别是破解文文件与映像 ...

  3. oracle 删除用户,提示“无法删除当前已连接的用户”

    1. 首先查询出该用户的登录情况,注意用户名必须是大写 SQL> select username,sid,serial# from v$session where username = 'XST ...

  4. 并发编程(3)——ThreadPoolExecutor

    ThreadPoolExecutor 1. ctl(control state) 线程池控制状态,包含两个概念字段:workerCount(线程有效数量)和runState(表示是否在运行.关闭等状态 ...

  5. 关于Java虚拟机运行时数据区域的总结

    Java虚拟机运行时数据区域 程序计数器(Program Counter) 程序计数器作为一个概念模型,这个是用来指示下一条需要执行的字节码指令在哪. Java的多线程实际上是通过线程轮转做到的,如果 ...

  6. .NETCore C# 中级篇2-4 一文带你完全弄懂正则表达式

    .NETCoreCSharp 中级篇2-4 本节内容为正则表达式的使用 简介 有的时候,你是否有过这种需求:判断一个Ip地址.邮箱.密码规则是否合法.如果让你使用if一类的传统方法进行处理,你肯定会被 ...

  7. 汇总VSCode中比较好用的插件

    使用vscode编辑器两年的时间,总结出前端一些比较方便的插件 1. Auto Close Tag 自动添加HTML / XML关闭标签 2. Auto Complete Tag 自动完成标签 3 A ...

  8. hadoop2.7之作业提交详解(下)

    接着作业提交详解(上)继续写:在上一篇(hadoop2.7之作业提交详解(上))中已经讲到了YARNRunner.submitJob() [WordCount.main() -> Job.wai ...

  9. Throughput Controller

    吞吐量控制器(Throughput Controller)介绍 作用:控制其子节点的执行次数与负载比例分配 Total Executions: 整个测试计划中的总执行次数 Percent Execut ...

  10. Scrapy爬虫框架学习

    一.Scrapy框架简介 1. 下载页面 2. 解析 3. 并发 4. 深度 二.安装 linux下安装 pip3 install scrapy windows下安装 a.pip3 install w ...