LOJ139 树链剖分
感觉这已经不能说是模板了吧......
解析:
难点在于换根后对子树进行的操作,设rt为当前根节点,u为操作子树:
u=rt时,就是对整棵树操作,没事么好说的。
rt不在u的子树范围内,操作对象就是u的子树。
rt在u的子树范围内,操作范围就是整棵树减去u-rt路径上深度最小的点(可以用线段树维护该点)的子树(不包括u)。
(可以画图模拟一下,注意这里我所说的某个节点的子树都是以1为根的情况)。
代码:
1 #include <bits/stdc++.h>
2 #define ll long long
3 using namespace std;
4 const int N = 1e5 + 10, inf = 1e9;
5 int head[N], to[N << 1], nxt[N << 1], tot;
6 int n, m, cnt, rt = 1;
7 ll val[N];
8 int dep[N], size[N], top[N], fa[N], son[N], id[N], rev[N];
9 int opt, a, b, c;
10 struct node {
11 int minp;
12 ll sum, lazy;
13 }t[N << 2];
14 void add(int a, int b) {
15 nxt[++ tot] = head[a], head[a] = tot, to[tot] = b;
16 }
17 void dfs1(int u, int f) {
18 size[u] = 1;
19 for (int i = head[u]; i; i = nxt[i]) {
20 int v = to[i];
21 if (v == f) continue;
22 fa[v] = u;
23 dep[v] = dep[u] + 1;
24 dfs1(v, u);
25 size[u] += size[v];
26 if (size[v] > size[son[u]]) son[u] = v;
27 }
28 }
29 void dfs2(int u, int t) {
30 top[u] = t;
31 id[u] = ++ cnt;
32 rev[cnt] = u;
33 if(!son[u]) return ;
34 dfs2(son[u], t);
35 for (int i = head[u]; i; i = nxt[i]) {
36 int v = to[i];
37 if (v != fa[u] && v != son[u]) dfs2(v, v);
38 }
39 }
40 namespace SegmentTree {
41 #define mid ((l + r) >> 1)
42 #define lson k << 1, l, mid
43 #define rson k << 1 | 1, mid + 1, r
44 int tmin(int a, int b) {//返回深度更小的点
45 if (a == inf) return b;
46 if (b == inf) return a;
47 if (dep[a] < dep[b]) return a;
48 else return b;
49 }
50 void pushup(int k) {//更新信息
51 t[k].sum = t[k << 1].sum + t[k << 1 | 1].sum;
52 t[k].minp = tmin(t[k << 1].minp, t[k << 1 | 1].minp);
53 }
54 void pushdown(int k, int l, int r) {//标记下传
55 if (!t[k].lazy) return ;
56 t[k << 1].lazy += t[k].lazy;
57 t[k << 1 | 1].lazy += t[k].lazy;
58 t[k << 1].sum += (mid - l + 1) * t[k].lazy;
59 t[k << 1 | 1].sum += (r - mid) * t[k].lazy;
60 t[k].lazy = 0;
61 }
62 void build(int k, int l, int r) {//建树
63 if (l == r) {
64 t[k].minp = rev[l];
65 t[k].sum = val[rev[l]];
66 return ;
67 }
68 build(lson), build(rson);
69 pushup(k);
70 }
71 void update(int k, int l, int r, int L, int R, ll v) {//更新权值
72 if (L <= l && R >= r) {
73 t[k].sum += (r - l + 1) * v;
74 t[k].lazy += v;
75 return ;
76 }
77 pushdown(k, l, r);
78 if (L <= mid) update(lson, L, R, v);
79 if (R > mid) update(rson, L, R, v);
80 pushup(k);
81 }
82 ll query(int k, int l, int r, int L, int R) {
83 ll ans = 0;
84 if (L <= l && R >= r) return t[k].sum;
85 pushdown(k, l, r);
86 if (L <= mid) ans += query(lson, L, R);
87 if (R > mid) ans += query(rson, L, R);
88 return ans;
89 }
90 int find(int k, int l, int r, int L, int R) {
91 int x = inf;
92 if (R < L) return inf;
93 if (L <= l && R >= r) return t[k].minp;//返回树中节点编号
94 if (L <= mid) x = tmin(x, find(lson, L, R));
95 if (R > mid) x = tmin(x, find(rson, L, R));
96 return x;
97 }
98 int lca(int a, int b) {
99 while (top[a] != top[b]) {
100 if (dep[top[a]] < dep[top[b]]) swap(a, b);
101 a = fa[top[a]];
102 }
103 if (dep[a] > dep[b]) swap(a, b);
104 return a;
105 }
106 int Upto(int a, int b) {//返回u-r链上(除u)深度最小的点
107 int ans = inf;
108 while (top[a] != top[b]) {
109 if (dep[top[a]] < dep[top[b]]) swap(a, b);
110 if (top[a] != b) ans = tmin(ans, find(1, 1, n, id[top[a]], id[a]));
111 else ans = tmin(ans, find(1, 1, n, id[top[a]] + 1, id[a]));//不能包括b
112 a = fa[top[a]];
113 }
114 if (dep[a] > dep[b]) swap(a, b);
115 ans = tmin(ans, find(1, 1, n, id[a] + 1, id[b]));
116 return ans;
117 }
118 int check(int a) {//判断三种类型中的哪一种
119 if (a == rt) return 0;
120 int L = lca(a, rt);
121 if (L == a) return Upto(a, rt);
122 else return -1;
123 }
124 void Add_Chain(int a, int b, ll w) {//修改路径上的节点权值
125 while (top[a] != top[b]) {
126 if (dep[top[a]] < dep[top[b]]) swap(a, b);
127 update(1, 1, n, id[top[a]], id[a], w);
128 a = fa[top[a]];
129 }
130 if (dep[a] > dep[b]) swap(a, b);
131 update(1, 1, n, id[a], id[b], w);
132 }
133 ll Ask_Chain(int a, int b) {//查询路径节点权值和
134 ll ans = 0;
135 while (top[a] != top[b]) {
136 if(dep[top[a]] < dep[top[b]]) swap(a, b);
137 ans += query(1, 1, n, id[top[a]], id[a]);
138 a = fa[top[a]];
139 }
140 if (dep[a] > dep[b]) swap(a, b);
141 ans += query(1, 1, n, id[a], id[b]);
142 return ans;
143 }
144 void Add_Tree(int u, ll v) {//修改子树权值
145 int type = check(u);
146 if (!type) update(1, 1, n, 1, n, v);
147 else if (type > 0) {
148 update(1, 1, n, 1, n, v);
149 update(1, 1, n, id[type], id[type] + size[type] - 1, -v);
150 } else update(1, 1, n, id[u], id[u] + size[u] - 1, v);
151 }
152 ll Ask_Tree(int u) {
153 int type = check(u);
154 if (!type) return query(1, 1, n, 1, n);
155 else if (type > 0) {
156 //一定要写type>0,一开始我写的type(实际意思是type!=0)
157 //不然一直都是RE
158 ll ans = query(1, 1, n, id[type], id[type] + size[type] - 1);
159 return query(1, 1, n, 1, n) - ans;
160 } else return query(1, 1, n, id[u], id[u] + size[u] - 1);
161 }
162 }
163 using namespace SegmentTree;
164 int main() {
165 scanf("%d", &n);;
166 for (int i = 1; i <= n; i ++) scanf("%lld", &val[i]);
167 for (int i = 2; i <= n; i ++) {
168 scanf("%d", &a);
169 add(i, a), add(a, i);
170 }
171 dep[1] = 1;
172 dfs1(1, 0);
173 dfs2(1, 1);
174 build(1, 1, n);
175 scanf("%d", &m);
176 while (m --) {
177 scanf("%d", &opt);
178 if (opt == 1) {
179 scanf("%d", &a);
180 rt = a;
181 } else if (opt == 2) {
182 scanf("%d %d %d", &a, &b, &c);
183 Add_Chain(a, b, c);
184 } else if (opt == 3) {
185 scanf("%d %d", &a, &b);
186 Add_Tree(a, b);
187 } else if (opt == 4) {
188 scanf("%d %d", &a, &b);
189 printf("%lld\n", Ask_Chain(a, b));
190 } else {
191 scanf("%d", &a);
192 printf("%lld\n", Ask_Tree(a));
193 }
194 }
195 return 0;
196 }
代码量有点大,调试有点小困难。。。
LOJ139 树链剖分的更多相关文章
- 【loj#139】树链剖分
#139. 树链剖分 题目描述 这是一道模板题. 给定一棵 $n$个节点的树,初始时该树的根为 111 号节点,每个节点有一个给定的权值.下面依次进行 $m$ 个操作,操作分为如下五种类型: 换根:将 ...
- BZOJ 3626: [LNOI2014]LCA [树链剖分 离线|主席树]
3626: [LNOI2014]LCA Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 2050 Solved: 817[Submit][Status ...
- BZOJ 1984: 月下“毛景树” [树链剖分 边权]
1984: 月下“毛景树” Time Limit: 20 Sec Memory Limit: 64 MBSubmit: 1728 Solved: 531[Submit][Status][Discu ...
- codevs 1228 苹果树 树链剖分讲解
题目:codevs 1228 苹果树 链接:http://codevs.cn/problem/1228/ 看了这么多树链剖分的解释,几个小时后总算把树链剖分弄懂了. 树链剖分的功能:快速修改,查询树上 ...
- 并查集+树链剖分+线段树 HDOJ 5458 Stability(稳定性)
题目链接 题意: 有n个点m条边的无向图,有环还有重边,a到b的稳定性的定义是有多少条边,单独删去会使a和b不连通.有两种操作: 1. 删去a到b的一条边 2. 询问a到b的稳定性 思路: 首先删边考 ...
- 树链剖分+线段树 CF 593D Happy Tree Party(快乐树聚会)
题目链接 题意: 有n个点的一棵树,两种操作: 1. a到b的路径上,给一个y,对于路径上每一条边,进行操作,问最后的y: 2. 修改某个条边p的值为c 思路: 链上操作的问题,想树链剖分和LCT,对 ...
- 树链剖分+线段树 HDOJ 4897 Little Devil I(小恶魔)
题目链接 题意: 给定一棵树,每条边有黑白两种颜色,初始都是白色,现在有三种操作: 1 u v:u到v路径(最短)上的边都取成相反的颜色 2 u v:u到v路径上相邻的边都取成相反的颜色(相邻即仅有一 ...
- bzoj2243树链剖分+染色段数
终于做了一道不是一眼出思路的代码题(⊙o⊙) 之前没有接触过这种关于染色段数的题目(其实上课好像讲过),于是百度了一下(现在思维能力好弱) 实际上每一段有用的信息就是总共有几段和两段各是什么颜色,在开 ...
- bzoj3631树链剖分
虽然是水题1A的感觉太爽了O(∩_∩)O~ 题意相当于n-1次树上路径上每个点权值+1,最后问每个点的权值 本来想写线段树,写好了change打算框架打完了再来补,结果打完发现只是区间加和单点查 前缀 ...
随机推荐
- 用kubeadm简单部署k8s
一.环境准备 1.三台CentOS6.7虚拟机 master:192.168.0.54 注意:主节点最好是2颗cpu,否则在k8s控制平面初始化的时候会报错: node1:192.168.0.68 n ...
- WPF 截图控件之绘制方框与椭圆(四) 「仿微信」
前言 接着上周写的截图控件继续更新 绘制方框与椭圆. 1.WPF实现截屏「仿微信」 2.WPF 实现截屏控件之移动(二)「仿微信」 3.WPF 截图控件之伸缩(三) 「仿微信」 正文 有开发者在B站反 ...
- 清北学堂 2020 国庆J2考前综合强化 Day7
目录 1. 题目 T1 魔力石 题目描述 Sol T2 和 题目描述 Sol T3 数对 题目描述 Sol T4 海豹王国 题目描述 Sol 考场策略 1. 题目 T1 魔力石 题目描述 题目描述 小 ...
- 服务器配置IP
1.服务器系统一般有两个或多个网卡.在企业中一般给服务器网卡配一个可连外网的IP,如172.16.20.22 255.255.255.0 172.16.20.1 方便联网下载安装部分软件,若没有VPN ...
- Pinhole类声明和实现
针孔相机,带旋转,移动等功能. 类声明: #pragma once #ifndef __PINHOLE_HEADER__ #define __PINHOLE_HEADER__ #include &qu ...
- Taurus.MVC 微服务框架 入门开发教程:项目部署:3、微服务应用程序版本升级:全站升级和局部模块升级。
系列目录: 本系列分为项目集成.项目部署.架构演进三个方向,后续会根据情况调整文章目录. 本系列第一篇:Taurus.MVC V3.0.3 微服务开源框架发布:让.NET 架构在大并发的演进过程更简单 ...
- Git 使用技巧(一):合并分支
在合并分支之前最好保证你所有的分支都是最新的,所以你可以使用 git pull origin branchName 来拉取远程仓库到本地仓库. 假如有一个 dev 分支需要合并到 master 分支中 ...
- CM311-1a(S905L3系列)玩转桌面
那安装了ambian后,玩转桌面(安装GUI桌面环境)有没有可能呢?那肯定啊!那桌面有什么用?当然有用,多一种玩法,可以写写代码,上网冲浪,学习linux语法什么的.而且单主机只要40左右,想想看可以 ...
- mysql验证隔离级别
mysql更改隔离级别 参考https://blog.csdn.net/qq_21299835/article/details/121189565 关闭mysql事务自动提交:set autocomm ...
- DataGridView控件绑定数据之后,置顶操作
一个小小的置顶,就搞了半个小时,还是记录一下吧. 1.第一个问题就是datatable的插入只能是Insert DataRow,但是获取选中的行,都是DataGridViewRow,不能直接转换. 找 ...