BZOJ_4034 [HAOI2015]树上操作 【树链剖分dfs序+线段树】
一 题目
二 分析
树链剖分的题,这里主要用到了$dfs$序,这题比较简单的就是不用求$lca$。
1.和树链剖分一样,先用邻接链表建双向图。
2.跑两遍$dfs$,其实这题可以不这么写,主要是为了确定树型结构转线型后各节点的编号,以及各个链的$top$,$top$很关键,没有$top$就需要不断找父节点。
3.建线段树,这里一定一定一定要仔细,写太丑就会调很久。o(╯□╰)o
4.修改操作和常规线段树没有区别,但修改就需要对链上的$top$节点和父节点不断更新,知道找到根节点就可以了。
三 AC代码
1 /**************************************************************
2 Problem: 4034
3 User: Dybala21
4 Language: C++
5 Result: Accepted
6 Time:2752 ms
7 Memory:16844 kb
8 ****************************************************************/
9
10 #include <bits/stdc++.h>
11 using namespace std;
12 #define ll long long
13
14 const int MAXN = 1e5 + 14;
15 int n, m;
16 int cost[MAXN];
17 int e[MAXN][2];
18 struct Edge
19 {
20 int to, next;
21 }edge[MAXN*2];
22 int head[MAXN], tot;
23 int fa[MAXN];
24 int p[MAXN];
25 int deep[MAXN];
26 int size[MAXN];
27 int son[MAXN];
28 int top[MAXN];
29 int pos;
30 void init()
31 {
32 tot = 0, pos = 0;
33 memset(head, -1, sizeof(head));
34 memset(son, -1, sizeof(son));
35 }
36 void addedge(int u, int v)
37 {
38 edge[tot].to = v;
39 edge[tot].next = head[u];
40 head[u] = tot++;
41 }
42 void dfs(int u, int pre, int d)
43 {
44 fa[u] = pre;
45 deep[u] = d;
46 size[u] = 1;
47 for(int i = head[u]; i != -1; i = edge[i].next)
48 {
49 int v = edge[i].to;
50 if(v != pre)
51 {
52 dfs(v, u, d+1);
53 size[u] += size[v];
54 if(son[u] == -1 || size[v] > size[son[u]])
55 son[u] = v;
56 }
57 }
58 }
59 void dfs2(int u, int sp)
60 {
61 top[u] = sp;
62
63 if(son[u] != -1)
64 {
65 p[u] = ++pos;
66 dfs2(son[u], sp);
67 }
68 else
69 {
70 p[u] = ++pos;
71 return;
72 }
73
74 for(int i = head[u]; i != -1; i = edge[i].next)
75 {
76 int v = edge[i].to;
77 if(v != son[u] && v != fa[u])
78 dfs2(v, v);
79 }
80 }
81 struct Node
82 {
83 int l, r;
84 ll sum, lazy;;
85 }segTree[MAXN*3];
86 void build(int rt, int l, int r)
87 {
88 segTree[rt].l = l;
89 segTree[rt].r = r;
90 segTree[rt].lazy = 0;
91 segTree[rt].sum = 0;
92 if(l == r)
93 return;
94 int mid = (l + r) >> 1;
95 build(rt<<1, l, mid);
96 build(rt<<1|1, mid + 1, r);
97 }
98 void pushdown(int rt)
99 {
100 if(segTree[rt].l == segTree[rt].r)
101 return;
102 int mid = (segTree[rt].l + segTree[rt].r)>>1;
103 ll t = segTree[rt].lazy;
104 segTree[rt].lazy = 0;
105 segTree[rt<<1].lazy += t;
106 segTree[rt<<1|1].lazy += t;
107 segTree[rt<<1].sum += t*(mid-segTree[rt].l+1);
108 segTree[rt<<1|1].sum += t*(segTree[rt].r-mid);
109 }
110 void update(int rt, int l, int r, ll val)
111 {
112 if(segTree[rt].lazy != 0)
113 pushdown(rt);
114 if(segTree[rt].l == l && segTree[rt].r == r)
115 {
116 segTree[rt].sum += (r-l+1)*val;
117 segTree[rt].lazy += val;
118 return;
119 }
120 int mid = (segTree[rt].l + segTree[rt].r)>>1;
121 if(r <= mid)
122 update(rt<<1, l, r, val);
123 else if(l > mid)
124 update(rt<<1|1, l, r, val);
125 else
126 {
127 update(rt<<1, l, mid, val);
128 update(rt<<1|1, mid + 1, r, val);
129 }
130 segTree[rt].sum = segTree[rt<<1].sum + segTree[rt<<1|1].sum;
131 }
132 ll query(int rt, int l, int r)
133 {
134 if(segTree[rt].lazy)
135 pushdown(rt);
136 if(segTree[rt].l == l && segTree[rt].r == r)
137 return segTree[rt].sum;
138 int mid = (segTree[rt].l + segTree[rt].r)>>1;
139 if(r <= mid)
140 return query(rt<<1, l, r);
141 else if(l > mid)
142 return query(rt<<1|1, l, r);
143 else
144 {
145 ll res = 0;
146 res += query(rt<<1, l, mid);
147 res += query(rt<<1|1, mid+1, r);
148 return res;
149 }
150 }
151 ll query(int x)
152 {
153 ll ans = 0;
154 while(top[x] != 1)
155 {
156 ans += query(1, p[top[x]], p[x]);
157 x = fa[top[x]];
158 }
159 ans += query(1, 1, p[x]);
160 return ans;
161 }
162 int main()
163 {
164 //freopen("in.txt", "r", stdin);
165 //freopen("out.txt", "w", stdout);
166 init();
167 scanf("%d%d", &n, &m);
168 for(int i = 1; i <= n; i++)
169 {
170 scanf("%d", &cost[i]);
171 }
172 for(int i = 0; i < n-1; i++)
173 {
174 scanf("%d%d", &e[i][0], &e[i][1]);
175 addedge(e[i][0], e[i][1]);
176 addedge(e[i][1], e[i][0]);
177 }
178 dfs(1, 0, 0);
179 dfs2(1, 1);
180 build(1, 1, pos);
181 for(int i = 1; i <= n; i++)
182 update(1, p[i], p[i], cost[i]);
183 int op, x, xa;
184 for(int i = 0; i < m; i++)
185 {
186 scanf("%d", &op);
187 if(op == 1)
188 {
189 scanf("%d%d", &x, &xa);
190 update(1, p[x], p[x], xa);
191 }
192 else if(op == 2)
193 {
194 scanf("%d%d", &x, &xa);
195 update(1, p[x], p[x] + size[x] - 1, xa);
196 }
197 else
198 {
199 scanf("%d", &x);
200 printf("%lld\n", query(x) );
201 }
202 }
203 return 0;
204 }
205
BZOJ_4034 [HAOI2015]树上操作 【树链剖分dfs序+线段树】的更多相关文章
- BZOJ - 4196 软件包管理器 (树链剖分+dfs序+线段树)
题目链接 设白色结点为未安装的软件,黑色结点为已安装的软件,则: 安装软件i:输出结点i到根的路径上的白色结点的数量,并把结点i到根的路径染成黑色.复杂度$O(nlog^2n)$ 卸载软件i:输出结点 ...
- bzoj 4034 [HAOI2015]树上操作 入栈出栈序+线段树 / 树剖 维护到根距离和
题目大意 有一棵点数为 N 的树,以点 1 为根,且树点有边权.然后有 M 个 操作,分为三种: 操作 1 :把某个节点 x 的点权增加 a . 操作 2 :把某个节点 x 为根的子树中所有点的点权都 ...
- BZOJ 2286 树链剖分+DFS序+虚树+树形DP
第一次学习虚树,就是把无关的点去掉.S里维护一条链即可. #include <iostream> #include <cstring> #include <cstdio& ...
- BZOJ4012[HNOI2015]开店——树链剖分+可持久化线段树/动态点分治+vector
题目描述 风见幽香有一个好朋友叫八云紫,她们经常一起看星星看月亮从诗词歌赋谈到 人生哲学.最近她们灵机一动,打算在幻想乡开一家小店来做生意赚点钱.这样的 想法当然非常好啦,但是她们也发现她们面临着一个 ...
- BZOJ 2243:染色(树链剖分+区间合并线段树)
[SDOI2011]染色Description给定一棵有n个节点的无根树和m个操作,操作有2类:1.将节点a到节点b路径上所有点都染成颜色c:2.询问节点a到节点b路径上的颜色段数量(连续相同颜色被认 ...
- BZOJ 2243: [SDOI2011]染色 树链剖分 倍增lca 线段树
2243: [SDOI2011]染色 Time Limit: 20 Sec Memory Limit: 256 MB 题目连接 http://www.lydsy.com/JudgeOnline/pr ...
- [BZOJ - 2819] Nim 【树链剖分 / DFS序】
题目链接: BZOJ - 2819 题目分析 我们知道,单纯的 Nim 的必胜状态是,各堆石子的数量异或和不为 0 .那么这道题其实就是要求求出树上的两点之间的路径的异或和.要求支持单点修改. 方法一 ...
- POJ 2763 Housewife Wind 【树链剖分】+【线段树】
<题目链接> 题目大意: 给定一棵无向树,这棵树的有边权,这棵树的边的序号完全由输入边的序号决定.给你一个人的起点,进行两次操作: 一:该人从起点走到指定点,问你这段路径的边权总和是多少. ...
- 【XSY2667】摧毁图状树 贪心 堆 DFS序 线段树
题目大意 给你一棵有根树,有\(n\)个点.还有一个参数\(k\).你每次要删除一条长度为\(k\)(\(k\)个点)的祖先-后代链,问你最少几次删完.现在有\(q\)个询问,每次给你一个\(k\), ...
随机推荐
- HDU - 4462 Scaring the Birds
It's harvest season now! Farmer John plants a lot of corn. There are many birds living around his co ...
- PyQt5 问题集
PyQt5中遇到的一些问题 1.多线程中界面异步刷新 我这里需要给界面动态添加新的控件,但是多线程中似乎并不能直接更新页面? 对于逻辑和界面分离的情况,使用自定义信号的方式进行页面控件的动态添加.注意 ...
- Install wx
Ubuntu 16.04: 由于是PY交易, 实际上是安装wxPython: pip install -U \ -f https://extras.wxpython.org/wxPython4/ext ...
- Prometheus Monitoring Solution
Prometheus Monitoring Solution 普罗米修斯 https://prometheus.io/ 警报 监控 增强指标和警报 领先 开源监控解决方案 https://promet ...
- 使用 js 实现一个中文自动转换成拼音的工具库
使用 js 实现一个中文自动转换成拼音的工具库 中文 => zhong-wen 应用场景 SEO 友好, URL 自动转换 blogs 发布文章,自动化部署,自动生成 url 的 path (时 ...
- Emmet & VSCode
Emmet & VSCode Emmet - the essential toolkit for web-developers https://emmet.io/ https://emmet. ...
- Asp.NetCore 3.1demo发布使用Windows服务
Core之Windows服务 使用测试之前,先来简单了解一下 window自带的sc命令 ========install.bat set serviceName=你的服务名称 set serviceF ...
- NGK是如何运用IPFS分布式存储的?
整个夏季,除了天气的火热,还有的火热莫过于IPFS挖矿这个领域了.IPFS的概念火热到,你可以看到到处都在卖IPFS矿机.那么,是什么原因导致IPFS这么火呢?在这之前,我们先了解一下什么是IPFS技 ...
- 19_MySQL表的内连接
本节所涉及的SQL语句: -- 表连接查询 -- 查询每名员工(员工名字,编号)的部门信息(部门编号,部门名称) SELECT e.empno,e.ename,d.dname FROM t_emp e ...
- 微信小程序:应用生命周期
小程序的生命周期分为应用生命周期和页面生命周期. 应用指的是一个文件,是小程序的入口文件app.js,入口文件最外层方法名称是App,页面的js文件最外层是page,组件的js文件的最外层是compo ...