一道树剖的模板题

首先,由于本人比较懒,就把单点修改写成了区间修改,其实也没有有多大区别(关键是我不会写单点修改QAQ)

不得不说,树剖的码量比较大,调了一上午才勉强调完。

这道题要求我们支持 单点修改,区间最大值,区间的和 操作。

我们可以对线段树每个节点 维护一下他的 区间和,以及区间最大值。

其他的就和P3384(树剖模板题)就差不多了。

还有要注意的点是

1 int ans = -2147483647;

求区间和时 答案一定要赋一个负数,因为这道题每个节点的权值有小于 0 的,不赋的话就会爆。

我这个蒟蒻就在这里卡了好几回。

最后附上我自己的代码

  1 #include<iostream>
2 #include<cstdio>
3 #include<algorithm>
4 using namespace std;
5 const int N = 3e4+10;
6 string opt;
7 int n,m,x,y,tot,num;
8 int dfn[N],son[N],head[N],size[N],fa[N];
9 int dep[N],top[N],w[N],a[N];
10 struct node{
11 int to;
12 int net;
13 }e[N*2];
14 void add_(int x,int y){//加边操作
15 tot++;
16 e[tot].to = y;
17 e[tot].net = head[x];
18 head[x] = tot;
19 }
20 void get_tree(int x){//第一遍dfs求每个点的重儿子
21 dep[x] = dep[fa[x]] + 1;
22 size[x] = 1;
23 for(int i = head[x]; i; i = e[i].net){
24 int to = e[i].to;
25 if(to == fa[x]) continue;
26 fa[to] = x;
27 get_tree(to);
28 size[x] += size[to];
29 if(size[to] > size[son[x]]) son[x] = to;
30 }
31 }
32 void dfs(int x,int topp){//第二遍dfs求每个点的top
33 top[x] = topp;
34 dfn[x] = ++num;//每个点的dfs序,方便之后建线段树
35 w[dfn[x]] = a[x];
36 if(son[x]) dfs(son[x],topp);
37 for(int i = head[x]; i; i = e[i].net){
38 int to = e[i].to;
39 if(to == fa[x] || to == son[x]) continue;
40 dfs(to,to);
41 }
42 }
43 struct tree{//线段树常规操作
44 #define l(o) tr[o].lc
45 #define r(o) tr[o].rc
46 #define sum(o) tr[o].sum
47 #define add(o) tr[o].add
48 #define maxn(o) tr[o].maxn
49 struct qxh{
50 int lc,rc;
51 int maxn,add,sum;
52 }tr[N<<2];
53 void up(int o){
54 sum(o) = sum(o*2) + sum(o*2+1);
55 maxn(o) = max(maxn(o*2) , maxn(o*2+1));
56 }
57 void build(int o, int L,int R){//按每个点的dfs序建树
58 l(o) = L; r(o) = R;
59 if(L == R){
60 sum(o) = maxn(o) = w[L];
61 return ;
62 }
63 int mid = (L + R) / 2;
64 build(o*2,L,mid);
65 build(o*2+1,mid+1,R);
66 up(o);
67 }
68 void chenge(int o,int L,int R,int val){//单点修改变区间修改
69 if(L <= l(o) && R >= r(o)){
70 sum(o) = val;
71 maxn(o) = val;
72 return ;
73 }
74 int mid = (l(o) + r(o)) / 2;
75 if(L <= mid) chenge(o*2,L,R,val);
76 if(R > mid) chenge(o*2+1,L,R,val);
77 up(o);
78 }
79 int ask_sum(int o,int L,int R){//询问区间的和
80 int ans = 0;
81 if(L <= l(o) && R >= r(o)){
82 return sum(o);
83 }
84 int mid = (l(o) + r(o)) / 2;
85 if(L <= mid) ans += ask_sum(o*2,L,R);
86 if(R > mid) ans += ask_sum(o*2+1,L,R);
87 return ans;
88 }
89 int ask_max(int o,int L,int R){//区间最大值
90 int ans = -2147483647; //一定要初值为负数,否则就会炸掉
91 if(L <= l(o) && R >= r(o)){
92 return maxn(o);
93 }
94 int mid = (l(o) + r(o)) / 2;
95 if(L <= mid) ans = max(ans,ask_max(o*2,L,R));
96 if(R > mid) ans = max(ans,ask_max(o*2+1,L,R));
97 return ans;
98 }
99 }tree;
100 int query_sum(int x,int y){//求树上路径的和
101 int ans = 0;
102 while(top[x] != top[y]){//边跳边修改
103 if(dep[top[x]] < dep[top[y]]) swap(x,y);
104 ans += tree.ask_sum(1, dfn[top[x]] , dfn[x]);
105 x = fa[top[x]];
106 }
107 if(dep[x] > dep[y]) swap(x,y);//使dfn[x] ~dfn[y]这一段区间的序号保持有序
108 ans += tree.ask_sum(1,dfn[x],dfn[y]);
109 return ans;
110 }
111 int query_max(int x,int y){//求树上路径和,同上
112 int ans = -2147483647;//赋初值。。。。
113 while(top[x] != top[y]){
114 if(dep[top[x]] < dep[top[y]]) swap(x,y);
115 ans = max(ans,tree.ask_max(1,dfn[top[x]],dfn[x]));
116 x = fa[top[x]];
117 }
118 if(dep[x] > dep[y]) swap(x,y);
119 ans = max(ans,tree.ask_max(1,dfn[x],dfn[y]));
120 return ans;
121 }
122 int main(){
123 scanf("%d",&n);
124 for(int i = 1; i <= n-1; i++){
125 scanf("%d%d",&x,&y);
126 add_(x,y);//建双向边
127 add_(y,x);
128 }
129 for(int i = 1; i <= n; i++) scanf("%d",&a[i]);
130 get_tree(1);//预处理
131 dfs(1,1);
132 tree.build(1,1,n);
133 scanf("%d",&m);
134 while(m--){
135 cin>>opt;
136 scanf("%d%d",&x,&y);
137 if(opt == "CHANGE"){
138 tree.chenge(1,dfn[x],dfn[x],y);
139 }
140 if(opt == "QMAX"){
141 printf("%d\n",query_max(x,y));
142 }
143 if(opt == "QSUM"){
144 printf("%d\n",query_sum(x,y));
145 }
146 }
147 return 0;
148 }

代码写的比较丑QAQ ,不喜勿喷。。。。

其实树剖的大部分都是模板题,只要记住两遍dfs就差不多了。

树剖套线段树就是将树剖的模板和线段树的模板凑到一起,每次修改或查询的时候对每条重链或轻链所在的线段树有序区间进行修改或查询。

树剖也就这么多东西。。。

这道题也就结束了,如果看不懂的可以看看Treaker (我们上届一位巨佬,会各种奇奇怪怪的树)的题解,他写的也挺好的 %%%%%

想练习树剖的可以做一下下面这几道题

  1. 轻重链剖分
  2. 软件包管理器
  3. 松鼠的新家
  4. 月下毛景树
  5. 旅行
  6. 旅游
  7. 运输计划
  8. 天天爱跑步

这些都是我们可爱的Treaker学长留的好题(毒瘤题,每道题都要调很久)。。。QAQ

本篇题解到这里就结束了。撒花✿✿ヽ(°▽°)ノ✿

树剖未完待续。。。。。QAQ

P2590 树的统计的更多相关文章

  1. Luogu P2590 树的统计(树链剖分+线段树)

    题意 原文很清楚了 题解 重链剖分模板题,用线段树维护即可. #include <cstdio> #include <cstring> #include <algorit ...

  2. 洛谷 [P2590] 树的统计

    迷之TLE #include <iostream> #include <cstdio> #include <cstring> #include <algori ...

  3. P2590 [ZJOI2008]树的统计(树链剖分)

    P2590 [ZJOI2008]树的统计 虽然是入门树剖模板 但是我终于1A了(大哭) 懒得写啥了(逃 #include<iostream> #include<cstdio> ...

  4. 树链剖分【洛谷P2590】 [ZJOI2008]树的统计

    P2590 [ZJOI2008]树的统计 题目描述 一棵树上有n个节点,编号分别为1到n,每个节点都有一个权值w. 我们将以下面的形式来要求你对这棵树完成一些操作: I. CHANGE u t : 把 ...

  5. P2590 [ZJOI2008]树的统计(LCT)

    P2590 [ZJOI2008]树的统计 题目描述 一棵树上有n个节点,编号分别为1到n,每个节点都有一个权值w. 我们将以下面的形式来要求你对这棵树完成一些操作: I. CHANGE u t : 把 ...

  6. 洛谷——P2590 [ZJOI2008]树的统计(树链剖分模板练手)

    P2590 [ZJOI2008]树的统计 I. CHANGE u t : 把结点u的权值改为t II. QMAX u v: 询问从点u到点v的路径上的节点的最大权值 III. QSUM u v: 询问 ...

  7. 洛谷P2590 [ZJOI2008] 树的统计 [树链剖分]

    题目传送门 树的统计 题目描述 一棵树上有n个节点,编号分别为1到n,每个节点都有一个权值w. 我们将以下面的形式来要求你对这棵树完成一些操作: I. CHANGE u t : 把结点u的权值改为t ...

  8. Luogu P2590 [ZJOI2008]树的统计

    最近在学树剖,看到了这题就做了 [ZJOI2008]树的统计 思路 从题面可以知道,这题是树剖题(要求的和模板没什么区别呀喂 就是在普通的树剖上加了一个最大值 所以可以知道就是树剖+特殊的线段树 线段 ...

  9. 洛谷P2590 [ZJOI2008]树的统计 题解 树链剖分+线段树

    题目链接:https://www.luogu.org/problem/P2590 树链剖分模板题. 剖分过程要用到如下7个值: fa[u]:u的父节点编号: dep[u]:u的深度: size[u]: ...

随机推荐

  1. Android Studio或者Eclipse中的最常用的快捷键,最简单的,部分不适用eclipse

    重写方法:ctrl+shift+s  然后选择Generate 构建即可: 执行程序:shift+F10 多行注释:ctrl+shift+/ 单行注释:ctrl+/ 快速打印log:logr 快速复制 ...

  2. 如何使用Xdebug单步调试PHP游戏服务器

    参考文章:https://www.sourcetoad.com/resources/debugging-php-save-time-with-xdebugs-remote-autostart/ 配置参 ...

  3. 使用Docker构建PHP7.4 + Swoole + Redis镜像

    使用Docker构建PHP7.4 + Swoole + Redis镜像 Docker是一个用于开发,交付和运行应用程序的开放平台.开发者可以利用Docker来快速交付,测试和部署代码,从而大大减少编写 ...

  4. 石子合并2(环形求最优解 区间dp)

    题目描述 在一个圆形操场的四周摆放N堆石子,现要将石子有次序地合并成一堆.规定每次只能选相邻的2堆合并成新的一堆,并将新的一堆的石子数,记为该次合并的得分. 试设计出1个算法,计算出将N堆石子合并成1 ...

  5. 1090 Highest Price in Supply Chain (25 分)(模拟建树,找树的深度)牛客网过,pat没过

    A supply chain is a network of retailers(零售商), distributors(经销商), and suppliers(供应商)-- everyone invo ...

  6. for、forEach、map、for...in、for...of的区别以及能否终止循环的总结

    有时候面试会提到,用的时候又不在意,今天有空挨个做了测试,总结如下:

  7. PyTorch ResNet 使用与源码解析

    本章代码:https://github.com/zhangxiann/PyTorch_Practice/blob/master/lesson8/resnet_inference.py 这篇文章首先会简 ...

  8. 跟着兄弟连系统学习Linux-【day03】

    day03-20200529 p10.学习注意事项         linux严格区分大小写(与python有点像)         Linux中所有内容都是通过文件形式保存,通过命令执行设置参数,写 ...

  9. kali命令大全

    arch 显示机器的处理器架构(1)uname -m 显示机器的处理器架构(2)uname -r 显示正在使用的内核版本dmidecode -q 显示硬件系统部件 - (SMBIOS / DMI)hd ...

  10. 手把手带你体验鸿蒙 harmonyOS

    wNlRGd.png 前言 本文已经收录到我的 Github 个人博客,欢迎大佬们光临寒舍: 我的 GIthub 博客 学习导图 image.png 一.为什么要尝鲜 harmonyos? wNlfx ...