(题面来自洛谷)

题目描述

有一棵点数为 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】树上操作的更多相关文章

  1. 【BZOJ4034】[HAOI2015]树上操作 树链剖分+线段树

    [BZOJ4034][HAOI2015]树上操作 Description 有一棵点数为 N 的树,以点 1 为根,且树点有边权.然后有 M 个 操作,分为三种: 操作 1 :把某个节点 x 的点权增加 ...

  2. HAOI2015 树上操作

    HAOI2015 树上操作 题目描述 有一棵点数为 N 的树,以点 1 为根,且树点有边权.然后有 M 个操作,分为三种:操作 1 :把某个节点 x 的点权增加 a .操作 2 :把某个节点 x 为根 ...

  3. bzoj千题计划242:bzoj4034: [HAOI2015]树上操作

    http://www.lydsy.com/JudgeOnline/problem.php?id=4034 dfs序,树链剖分 #include<cstdio> #include<io ...

  4. bzoj4034[HAOI2015]树上操作 树链剖分+线段树

    4034: [HAOI2015]树上操作 Time Limit: 10 Sec  Memory Limit: 256 MBSubmit: 6163  Solved: 2025[Submit][Stat ...

  5. 树剖||树链剖分||线段树||BZOJ4034||Luogu3178||[HAOI2015]树上操作

    题面:P3178 [HAOI2015]树上操作 好像其他人都嫌这道题太容易了懒得讲,好吧那我讲. 题解:第一个操作和第二个操作本质上是一样的,所以可以合并.唯一值得讲的点就是:第二个操作要求把某个节点 ...

  6. P3178 [HAOI2015]树上操作

    P3178 [HAOI2015]树上操作 思路 板子嘛,其实我感觉树剖没啥脑子 就是debug 代码 #include <bits/stdc++.h> #define int long l ...

  7. bzoj 4034: [HAOI2015]树上操作 树链剖分+线段树

    4034: [HAOI2015]树上操作 Time Limit: 10 Sec  Memory Limit: 256 MBSubmit: 4352  Solved: 1387[Submit][Stat ...

  8. bzoj 4034: [HAOI2015]树上操作 (树剖+线段树 子树操作)

    4034: [HAOI2015]树上操作 Time Limit: 10 Sec  Memory Limit: 256 MBSubmit: 6779  Solved: 2275[Submit][Stat ...

  9. BZOJ.4034 [HAOI2015]树上操作 ( 点权树链剖分 线段树 )

    BZOJ.4034 [HAOI2015]树上操作 ( 点权树链剖分 线段树 ) 题意分析 有一棵点数为 N 的树,以点 1 为根,且树点有边权.然后有 M 个 操作,分为三种: 操作 1 :把某个节点 ...

  10. 洛谷P3178 [HAOI2015]树上操作(dfs序+线段树)

    P3178 [HAOI2015]树上操作 题目链接:https://www.luogu.org/problemnew/show/P3178 题目描述 有一棵点数为 N 的树,以点 1 为根,且树点有边 ...

随机推荐

  1. Redis学习笔记(八)——持久化

    一.介绍 Redis的所有的数据都存在内存中,然后不定期的通过异步方式保存到磁盘上(这称为"半持久化模式"):也可以把每一次数据变化都写入到一个append only file(a ...

  2. MongoDB复制 --- MongoDB基础用法(五)

    复制 MongoDB复制是将数据同步在多个服务器的过程. 复制提供了数据的冗余备份,并在多个服务器上存储数据副本,提高了数据的可用性, 并可以保证数据的安全性. 复制还允许您从硬件故障和服务中断中恢复 ...

  3. Kubernetes Scheduler浅析

    概述 Kubernetes 调度器(Scheduler)是Kubernetes的核心组件:用户或者控制器创建Pod之后,调度器通过 kubernetes 的 watch 机制来发现集群中新创建且尚未被 ...

  4. 【总结】zookeeper

    一.入门 1.概述 Zookeeper 是一个开源的分布式的,为分布式应用提供协调服务的 Apache 项目 2.zookeeper特点 (1)Zookeeper:一个领导者(Leader),多个跟随 ...

  5. ubuntu裸机启动python博客项目

    关注公众号"轻松学编程"了解更多. 在linux的ubuntu(18.04)中正确安装python的命令: sudo apt clean sudo apt update sudo ...

  6. Java入门(2)

    阅读书目:Java入门经典(第7版) 作者:罗格斯·卡登海德 一个简单的计算平方根的程序: 1 package com.java24hours; 2 3 public class Root { 4 p ...

  7. 2.5远程仓的库使用-2.7Git别名

    2.5 远程仓库的使用 查看远程仓库 git remote # -v 选项会显示需要读写远程仓库使用的 Git 保存的简写与其对应的 URL 添加远程仓库 git remote add <sho ...

  8. 4G模块与WIFI模块的工作及应用区别

    在物联网行业中,4G模块和wifi模块经经常会被使用,但是由于网络不同,二者的工作原理和场景还是有很大的不同,本篇主要讲讲4G模块和WIFI模块的功能和应用场景 什么是4G模块? 4G模块是基于4G网 ...

  9. Integer a=1,b=1,c=500,d=500;a==b,c==d;

    public class test { public static void main(String[] args){ Integer a=1,b=1,c=500,d=500; System.out. ...

  10. (1)ElasticSearch搭配Kibana在linux环境的部署

    1.简介 这个章节主要介绍ElasticSearch+Kibana两个组件在linux环境的部署步骤,以及在部署过程中遇到问题解决,暂就不涉及集群部署知识点,后面章节再详细讲解这块.下面让我们来简单了 ...