【HAOI2015】树上操作
(题面来自洛谷)
题目描述
有一棵点数为 N 的树,以点 1 为根,且树点有边权。然后有 M 个操作,分为三种:
操作 1 :把某个节点 x 的点权增加 a 。
操作 2 :把某个节点 x 为根的子树中所有点的点权都增加 a 。
操作 3 :询问某个节点 x 到根的路径中所有点的点权和。
数据范围:N <= 1e5
分析:简化版的ETT。建立括号序列,操作1、3都很容易解决。为了实现操作2,给序列上的点打标记,表示这里存储的是原节点权值的正/负值。用线段树维护区间和,上推时分别合并正负节点数,区间修改时每个线段树节点值\(sum+=val*(pos-neg)\),这样就实现了正负节点的区分操作。同时要求移植子树就变成了ETT的模板题,用Splay/FHQ维护即可。
代码:
#include <iostream>
#include <cstdio>
#include <cstring>
const int maxn(100010);
typedef long long LL;
using namespace std;
int n, m;
LL wt[maxn];
int head[maxn], etop;
struct E {
int to, nxt;
} edge[maxn<<1];
inline void insert(int u, int v) {
edge[++etop] = (E) {v, head[u]};
head[u] = etop;
}
int fst[maxn], sec[maxn], tmr;
LL dat[maxn<<1];
bool cat[maxn<<1];
void dfs(int u, int pre) {
fst[u] = ++tmr;
dat[tmr] = wt[u];
cat[tmr] = 1;
for (int i = head[u], v; i; i = edge[i].nxt) {
if ((v = edge[i].to) == pre) continue;
dfs(v, u);
}
sec[u] = ++tmr;
dat[tmr] = -wt[u];
cat[tmr] = 0;
return;
}
namespace Seg_tree {
#define lc (nd<<1)
#define rc ((nd<<1)|1)
#define mid ((l + r) >> 1)
struct node {
LL sum;
int pos, neg;
friend node operator + (node a, node b) {
return (node) {a.sum + b.sum, a.pos + b.pos, a.neg + b.neg};
}
friend node operator * (node a, LL b) {
return (node) {a.sum + b * (a.pos-a.neg), a.pos, a.neg};
}
} seg[maxn<<3];
LL tag[maxn<<3];
inline void update(int nd) {
seg[nd] = seg[lc] + seg[rc];
}
inline void put_tag(int nd, LL val) {
seg[nd] = seg[nd] * val;
tag[nd] += val;
}
inline void push_down(int nd) {
put_tag(lc, tag[nd]);
put_tag(rc, tag[nd]);
tag[nd] = 0;
}
void build(int nd, int l, int r) {
if (l == r) {
seg[nd] = (node) {dat[l], cat[l], !cat[l]};
return;
}
build(lc, l, mid);
build(rc, mid+1, r);
update(nd);
}
void add(int nd, int l, int r, int ql, int qr, LL val) {
if (l >= ql && r <= qr) {
put_tag(nd, val);
return;
}
if (r < ql || l > qr) return;
push_down(nd);
add(lc, l, mid, ql, qr, val);
add(rc, mid+1, r, ql, qr, val);
update(nd);
}
LL query(int nd, int l, int r, int ql, int qr) {
if (l >= ql && r <= qr) {
return seg[nd].sum;
}
if (r < ql || l > qr) return 0;
push_down(nd);
return query(lc, l, mid, ql, qr) + query(rc, mid+1, r, ql, qr);
}
} using namespace Seg_tree;
int main() {
scanf("%d %d", &n, &m);
for (int i = 1; i <= n; ++i) scanf("%lld", &wt[i]);
int u, v;
for (int i = 1; i < n; ++i) {
scanf("%d %d", &u, &v);
insert(u, v), insert(v, u);
}
dfs(1, 0);
build(1, 1, 2*n);
int opt;
while (m--) {
scanf("%d %d", &opt, &u);
if (opt == 3) {
printf("%lld\n", query(1, 1, 2*n, 1, fst[u]));
continue;
}
scanf("%d", &v);
if (opt == 1) {
add(1, 1, 2*n, fst[u], fst[u], v);
add(1, 1, 2*n, sec[u], sec[u], v);
} else add(1, 1, 2*n, fst[u], sec[u], v);
}
return 0;
}
【HAOI2015】树上操作的更多相关文章
- 【BZOJ4034】[HAOI2015]树上操作 树链剖分+线段树
[BZOJ4034][HAOI2015]树上操作 Description 有一棵点数为 N 的树,以点 1 为根,且树点有边权.然后有 M 个 操作,分为三种: 操作 1 :把某个节点 x 的点权增加 ...
- HAOI2015 树上操作
HAOI2015 树上操作 题目描述 有一棵点数为 N 的树,以点 1 为根,且树点有边权.然后有 M 个操作,分为三种:操作 1 :把某个节点 x 的点权增加 a .操作 2 :把某个节点 x 为根 ...
- bzoj千题计划242:bzoj4034: [HAOI2015]树上操作
http://www.lydsy.com/JudgeOnline/problem.php?id=4034 dfs序,树链剖分 #include<cstdio> #include<io ...
- bzoj4034[HAOI2015]树上操作 树链剖分+线段树
4034: [HAOI2015]树上操作 Time Limit: 10 Sec Memory Limit: 256 MBSubmit: 6163 Solved: 2025[Submit][Stat ...
- 树剖||树链剖分||线段树||BZOJ4034||Luogu3178||[HAOI2015]树上操作
题面:P3178 [HAOI2015]树上操作 好像其他人都嫌这道题太容易了懒得讲,好吧那我讲. 题解:第一个操作和第二个操作本质上是一样的,所以可以合并.唯一值得讲的点就是:第二个操作要求把某个节点 ...
- P3178 [HAOI2015]树上操作
P3178 [HAOI2015]树上操作 思路 板子嘛,其实我感觉树剖没啥脑子 就是debug 代码 #include <bits/stdc++.h> #define int long l ...
- bzoj 4034: [HAOI2015]树上操作 树链剖分+线段树
4034: [HAOI2015]树上操作 Time Limit: 10 Sec Memory Limit: 256 MBSubmit: 4352 Solved: 1387[Submit][Stat ...
- bzoj 4034: [HAOI2015]树上操作 (树剖+线段树 子树操作)
4034: [HAOI2015]树上操作 Time Limit: 10 Sec Memory Limit: 256 MBSubmit: 6779 Solved: 2275[Submit][Stat ...
- BZOJ.4034 [HAOI2015]树上操作 ( 点权树链剖分 线段树 )
BZOJ.4034 [HAOI2015]树上操作 ( 点权树链剖分 线段树 ) 题意分析 有一棵点数为 N 的树,以点 1 为根,且树点有边权.然后有 M 个 操作,分为三种: 操作 1 :把某个节点 ...
- 洛谷P3178 [HAOI2015]树上操作(dfs序+线段树)
P3178 [HAOI2015]树上操作 题目链接:https://www.luogu.org/problemnew/show/P3178 题目描述 有一棵点数为 N 的树,以点 1 为根,且树点有边 ...
随机推荐
- Spring Boot学习笔记(二)——HelloWorld实现
提示:要在Eclipse里使用Spring Boot,首先要安装STS插件,前面我们已经安装了STS插件了,可以创建Spring Boot项目了. 1.创建项目: 新建项目,选择Spring Boot ...
- puk2367 拓扑排序
Description The system of Martians' blood relations is confusing enough. Actually, Martians bud when ...
- Filebeat 根据不同的日志设置不同的索引
平时在物理机上使用 Filebeat 收集日志时,会编写多个 filebeat 配置文件然后启动多个 filebeat 进程来收集不同路径下的日志并设置相对应的索引.那么如果将所有的日志路径都写到一个 ...
- 浅谈 Johnson 算法
目录 前言 引入 算法概述 算法流程 正确性证明 代码实现 结语 前言 Johnson 和 Floyd 一样是用来解决无负环图上的全源最短路. 在稀疏图上的表现远远超过 Floyd,时间复杂度 \(O ...
- 简单Emacs配置
(global-set-key [f9] 'compile-file) (global-set-key [f10] 'gud-gdb) (global-set-key (kbd "C-s&q ...
- dhcp、tftp、httpd、pxe安装CentOS6.9
虚拟机网络设置 要xshell连接虚拟机注意设置VMware Network Adapter VMnet2在同一网段 1.利用光盘配置本地yum源 [root@ZYB ~]# mount -r /de ...
- 痞子衡嵌入式:RT-UFL - 一个适用全平台i.MXRT的超级下载算法设计
大家好,我是痞子衡,是正经搞技术的痞子.今天给大家带来的是痞子衡的开源项目 RT-UFL. 痞子衡在近两年多的i.MXRT客户项目支持过程中,遇到的一个相当高频的问题就是制作i.MXRT下载算法.我们 ...
- leetcode45:maximum depth of binary tree
题目描述 求给定二叉树的最大深度, 最大深度是指树的根结点到最远叶子结点的最长路径上结点的数量. Given a binary tree, find its maximum depth. The ma ...
- leetcode93:insert-interval
题目描述 给定一组不重叠的时间区间,在时间区间中插入一个新的时间区间(如果有重叠的话就合并区间). 这些时间区间初始是根据它们的开始时间排序的. 示例1: 给定时间区间[1,3],[6,9],在这两个 ...
- EFCore 5 新特性 `SaveChangesInterceptor`
EFCore 5 新特性 SaveChangesInterceptor Intro 之前 EF Core 5 还没正式发布的时候有发布过一篇关于 SaveChangesEvents 的文章,有需要看可 ...