题目

感觉这已经不能说是模板了吧......

解析:

难点在于换根后对子树进行的操作,设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 树链剖分的更多相关文章

  1. 【loj#139】树链剖分

    #139. 树链剖分 题目描述 这是一道模板题. 给定一棵 $n$个节点的树,初始时该树的根为 111 号节点,每个节点有一个给定的权值.下面依次进行 $m$ 个操作,操作分为如下五种类型: 换根:将 ...

  2. BZOJ 3626: [LNOI2014]LCA [树链剖分 离线|主席树]

    3626: [LNOI2014]LCA Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 2050  Solved: 817[Submit][Status ...

  3. BZOJ 1984: 月下“毛景树” [树链剖分 边权]

    1984: 月下“毛景树” Time Limit: 20 Sec  Memory Limit: 64 MBSubmit: 1728  Solved: 531[Submit][Status][Discu ...

  4. codevs 1228 苹果树 树链剖分讲解

    题目:codevs 1228 苹果树 链接:http://codevs.cn/problem/1228/ 看了这么多树链剖分的解释,几个小时后总算把树链剖分弄懂了. 树链剖分的功能:快速修改,查询树上 ...

  5. 并查集+树链剖分+线段树 HDOJ 5458 Stability(稳定性)

    题目链接 题意: 有n个点m条边的无向图,有环还有重边,a到b的稳定性的定义是有多少条边,单独删去会使a和b不连通.有两种操作: 1. 删去a到b的一条边 2. 询问a到b的稳定性 思路: 首先删边考 ...

  6. 树链剖分+线段树 CF 593D Happy Tree Party(快乐树聚会)

    题目链接 题意: 有n个点的一棵树,两种操作: 1. a到b的路径上,给一个y,对于路径上每一条边,进行操作,问最后的y: 2. 修改某个条边p的值为c 思路: 链上操作的问题,想树链剖分和LCT,对 ...

  7. 树链剖分+线段树 HDOJ 4897 Little Devil I(小恶魔)

    题目链接 题意: 给定一棵树,每条边有黑白两种颜色,初始都是白色,现在有三种操作: 1 u v:u到v路径(最短)上的边都取成相反的颜色 2 u v:u到v路径上相邻的边都取成相反的颜色(相邻即仅有一 ...

  8. bzoj2243树链剖分+染色段数

    终于做了一道不是一眼出思路的代码题(⊙o⊙) 之前没有接触过这种关于染色段数的题目(其实上课好像讲过),于是百度了一下(现在思维能力好弱) 实际上每一段有用的信息就是总共有几段和两段各是什么颜色,在开 ...

  9. bzoj3631树链剖分

    虽然是水题1A的感觉太爽了O(∩_∩)O~ 题意相当于n-1次树上路径上每个点权值+1,最后问每个点的权值 本来想写线段树,写好了change打算框架打完了再来补,结果打完发现只是区间加和单点查 前缀 ...

随机推荐

  1. k8s配置集ConfigMap详解

    ConfigMap介绍 ConfigMap和Secret是Kubernetes系统上两种特殊类型的存储卷,ConfigMap对象用于为容器中的应用提供配置文件等信息.但是比较敏感的数据,例如密钥.证书 ...

  2. 20220722-Java可变参数

    Java可变参数总结 来源:B站韩顺平老师的Java入门教学 代码示例如下: public void f(String str,int... nums){ 方法体; } 代码示例如下: public ...

  3. 虚拟机上安装Linux系统

    1,打开VMware,文件--新建虚拟机 2,选择自定义 3,选择VMware版本,下一步 4,选择稍后安装操作系统,下一步 5,选择Linux,版本我这里用的是centos7 6, 设置虚拟名称,设 ...

  4. 5.26 NOI 模拟

    \(T1\)石子与HH与HHの取 博弈是不可能会的 \(c_i\)相等,比较显然的\(Nim,\)直接前缀异或求一下 \(a_i=1,\)区间长度对\(2\)取模 结论\(:\)黑色石子严格大于白色个 ...

  5. SQL Server查询优化

    从上至下优化 看过一篇文章,印象深刻,里面将数据库查询优化分为四个大的方向 使用钞能力--给DB服务器加物理配置,内存啊,CPU啊,硬盘啊,全上顶配 替换存储系统--根据实际的业务情况选择不同的存储数 ...

  6. MySQL 连接超时:报错SQLSTATE[HY000] [2002] Connection timed out

    在网上找了一堆,结果全部是错的 后来,我明白了其实是设置问题. 当你的代码部署到服务器里的时候,你的mysql 的host 值 应该为 127.0.0.1 而不是 你的服务器ip 不然就会报错. 其实 ...

  7. 275. H 指数 II--Leetcode_暴力

    来源:力扣(LeetCode) 链接:https://leetcode.cn/problems/h-index-ii 著作权归领扣网络所有.商业转载请联系官方授权,非商业转载请注明出处. 题目的大意是 ...

  8. 虚拟机kali端口映射外网vps

    前言:我们常用的kali系统一般都是在虚拟机里面运行,这样在真实环境中外网是访问不到你的kali攻击机的,这时候我们就需要给kali映射一个外网vps. 一.在vps启动frp 服务端 安装frp并解 ...

  9. 《HelloGitHub》第 77 期

    兴趣是最好的老师,HelloGitHub 让你对编程感兴趣! 简介 HelloGitHub 分享 GitHub 上有趣.入门级的开源项目. https://github.com/521xueweiha ...

  10. uniapp+.net core 小程序获取手机号

    获取手机号 从基础库 2.21.2 开始,对获取手机号的接口进行了安全升级,以下是新版本接口使用指南.(旧版本接口目前可以继续使用,但建议开发者使用新版本接口,以增强小程序安全性) 因为需要用户主动触 ...