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打算框架打完了再来补,结果打完发现只是区间加和单点查 前缀 ...
随机推荐
- Java学习第五周
这周学习了异常与多线程,线程使用 Exception异常的分类: 1.编译时异常:继承自Exception的异常或者其子类,编译阶段就会报错 2.运行时异常:继承自RuntimeException的异 ...
- PostGresql listen与notify命令
LISTEN与NOTIFY命令 PostgreSQL提供了client端和其他client端通过服务器端进行消息通信的机制.这种机制 是通过LISTEN和NOTIFY命令来完成的. 1.LISTEN与 ...
- HTTP配置
目录 HTTP配置 虚拟主机 相同IP不同端口 不同IP相同端口 相同IP相同端口不同域名 Linux修改hosts文件 Windows修改hosts文件 配置https HTTP配置 虚拟主机 虚拟 ...
- Java中list集合自定义排序-2022新项目
一.业务场景 为了加快首页数据查询的效率,因此将首页查询的数据大多数都放在了缓存中,包括各种list集合数据.对这些 从缓存中获取的数据做了一个兜底处理,如果从缓存中没有获取到数据,则直接从数据库中去 ...
- java学习第二天面向对象.day07
变量的生命周期 成员变量:存储在堆内存中,随着对象的销毁而销毁 局部变量:存储在栈内存中,随着所定义方法的调用结束而销毁 局部变量存储在方法中,每次调用方法都会在栈空间开辟一块内存空间--栈帧,方法调 ...
- Markdown使用指南
1. Markdown是什么? Markdown是一种轻量级标记语言,它以纯文本形式(易读.易写.易更改)编写文档,并最终以HTML格式发布. Markdown也可以理解为将以MARKDOWN语法编写 ...
- 造数字(数位DP)
题面 JZM 想要创造两个数字 x 和 y,它们需要满足 x or y = T,且Lx ≤ x ≤ Rx, Ly ≤ y ≤ Ry,JZM 想知道 x and y 有多少种可能的不同的取值.若有多组 ...
- HDU6848改编题(弱化)——客星璀璨之夜(stars)
「 客星璀璨之夜 」(stars) " 虽然不清楚是不是那两人的力量 在那个风暴肆虐的夜晚,的确有一瞬 真的在那一瞬间,在云破天开的时候 透过空隙中看到的璀璨星空,不知为何倒映眼中不能忘怀 ...
- java数组---稀疏数组与数组之间的相互转化
public static void main(String[] args) { int[][]array1=new int[11][11]; array1[1][2]=1; array1[2][3] ...
- 【Java】学习路径49-练习:使用两个不同的线程类实现买票系统
练习:使用两个不同的线程类实现买票系统 请创建两个不同的线程类.一个测试类以及一个票的管理类. 其中票的管理类用于储存票的数量.两个线程类看作不同的买票方式. 步骤: 1.创建所需的类 App售票线程 ...