【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 为根,且树点有边 ...
随机推荐
- ATOM基础教程一使用前端插件emmet(16)
emmet简介 http://blog.csdn.net/zsl10/article/details/51956791 emmet的前身是Zen coding,从事Web前端开发的工程师对该插件并不陌 ...
- Mybatis---00Mybatis入门
一.什么是Mybatis Mybatis框架是一个半ORM框架.Mybatis是一个优秀的基于 java 的持久层框架,它内部封装了 jdbc,使开发者只需要关注 sql 语句本身,而不需要花费精力去 ...
- STM32入门系列-创建寄存器模板
介绍如何使用 KEIL5 软件创建寄存器模板, 方便之后使用寄存器方式来操作STM32开发板上的LED,让大家创建属于自己的寄存器工程模板. 获取工程模板的基础文件 首先我们在电脑任意位置创建一个文件 ...
- Java学习的第二十一天
1.综合实例 error异常:error指的是错误,通常是程序员不可能通过代码来解决的问题,底层环境或硬件问题,也就是说在程序中用户不用捕获error及任何error子类的异常. exception指 ...
- 基于Django的图书推荐系统和论坛
基于Django的图书推荐系统和论坛 关注公众号"轻松学编程"回复"图书系统"获取源码 一.基本功能 登录注册页面 基于协同过滤的图书的分类,排序,搜索,打分功 ...
- 从ReentrantLock加锁解锁角度分析AQS
本文用于记录在学习AQS时,以ReentrantLock为切入点,深入源码分析ReentrantLock的加锁和解锁过程. 同步器AQS的主要使用方式是继承,子类通过继承同步器并实现它的抽象方法来管理 ...
- Docker(12)- docker run 命令详解
如果你还想从头学起 Docker,可以看看这个系列的文章哦! https://www.cnblogs.com/poloyy/category/1870863.html 作用 创建一个新的容器并运行一个 ...
- 利用ms08_067入侵window xp sp1(English)版本
前几天上课,老师搬出实验,自己体验了一下 1.环境配置 需要准备kali(攻击机),window xp (我这里是sp1 英文版本,标题很清楚了),攻击机和目标靶机要在同意网段下我的kali(192. ...
- 激情的来源 Imagine how much you love it !
激情来自哪里?我想可能我找到了,精髓就在那个标题! 想象你有多么爱它!你就会爱上他,想象你有多么喜欢某一个东西,你很有可能就喜欢上他,着手去了解他,接触他. 如果带着这种想象状态的激情,工作和学习会有 ...
- IIC、SPI、UART协议总结
IIC 特点 1.Inter-Integrated Circuit,内部集成总线,半双工 2.短距离传输,有应答,速度较慢 3.SDA双向数据线,SCL时钟线 4.可以挂载多个设备,IIC设备有固化地 ...