题目:

有一棵点数为 N 的树,以点 1 为根,且树点有边权。然后有 M 个操作,分为三种:

操作 1 :把某个节点 x 的点权增加 a 。

操作 2 :把某个节点 x 为根的子树中所有点的点权都增加 a 。

操作 3 :询问某个节点 x 到根的路径中所有点的点权和。

题解:

ysf : 树链剖分大水题 !

lrd : 直接树剖不就好了嘛

gls : 这树剖不行吗 ?

lyc : ... ...

本人表示,当时真的脑袋抽了,忘了树剖就能搞...

但是我脑袋这么一抽就想出了一个\(O(nlogn)\)的解法.

我们处理出dfs序.

如图:



对应dfs序为:

\(1,2,3,-3,4,-4,-2,5,6,-6,-5,-1\)

然后对于所有的单点修改修改相应的入栈点和出栈点

对于一个子树修改就修改左端点为入栈序,右端点为出栈序的区间

对于一个查询就直接查询区间[1,入栈序]的权值和.

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long ll;
inline void read(ll &x){
x=0;char ch;bool flag = false;
while(ch=getchar(),ch<'!');if(ch == '-') ch=getchar(),flag = true;
while(x=10*x+ch-'0',ch=getchar(),ch>'!');if(flag) x=-x;
}
const ll maxn = 210010;
struct Edge{
ll to,next;
}G[maxn<<1];
ll head[maxn],cnt;
inline void add(ll u,ll v){
G[++cnt].to = v;
G[cnt].next = head[u];
head[u] = cnt;
}
#define v G[i].to
ll ind[maxn],dfs_clock,oud[maxn],idx[maxn];
void dfs(ll u,ll f){
ind[u] = ++ dfs_clock;
idx[dfs_clock] = u;
for(ll i = head[u];i;i=G[i].next){
if(v == f) continue;
dfs(v,u);
}
oud[u] = ++ dfs_clock;
idx[dfs_clock] = u;
}
#undef v
struct Node{
Node *ch[2];
ll val,lazy;
ll num1,num2;
void update(){
val = ch[0]->val + ch[1]->val;
num1 = ch[0]->num1 + ch[1]->num1;
num2 = ch[0]->num2 + ch[1]->num2;
}
}*null,mem[maxn<<2],*it,*root;
inline void init(){
it = mem;null = it++;
null->ch[0] = null->ch[1] = null;
null->val = null->lazy = null->num1 = null->num2 = 0;
root = null;
}
inline Node* newNode(){
Node *p = it++;p->ch[0] = p->ch[1] = null;
return p;
}
inline void pushdown(Node *p){
if(p == null || p->lazy == 0) return ;
if(p->ch[0] != null){
p->ch[0]->val += p->ch[0]->num1*p->lazy - p->ch[0]->num2*p->lazy;
p->ch[0]->lazy += p->lazy;
}
if(p->ch[1] != null){
p->ch[1]->val += p->ch[1]->num1*p->lazy - p->ch[1]->num2*p->lazy;
p->ch[1]->lazy += p->lazy;
}
p->lazy = 0;
}
inline void insert(Node* &p,ll l,ll r,ll pos,ll val,ll ty){
if(p == null) p = newNode();
if(l == r){
if(ty == 1) p->num1 = 1,p->num2 = 0;
else if(ty == -1) p->num1 = 0,p->num2 = 1;
p->val = p->num1*val - p->num2*val;
return ;
}
ll mid = l+r >> 1;
if(pos <= mid) insert(p->ch[0],l,mid,pos,val,ty);
else insert(p->ch[1],mid+1,r,pos,val,ty);
p->update();
}
inline void modify(Node *p,ll l,ll r,ll L,ll R,ll val){
if(L <= l &&r <= R){
p->lazy += val;
p->val += p->num1*val - p->num2*val;
return ;
}
pushdown(p);
ll mid = l+r >> 1;
if(L <= mid) modify(p->ch[0],l,mid,L,R,val);
if(R > mid) modify(p->ch[1],mid+1,r,L,R,val);
p->update();
}
inline ll query(Node *p,ll l,ll r,ll L,ll R){
if(L <= l && r <= R) return p->val;
pushdown(p);ll mid = l+r >> 1;
if(R <= mid) return query(p->ch[0],l,mid,L,R);
if(L > mid) return query(p->ch[1],mid+1,r,L,R);
return query(p->ch[0],l,mid,L,R) + query(p->ch[1],mid+1,r,L,R);
}
ll c[maxn];
int main(){init();
ll n,m;read(n);read(m);
for(ll i=1;i<=n;++i) read(c[i]);
for(ll i=1,u,v;i<n;++i){
read(u);read(v);
add(u,v);add(v,u);
}dfs(1,1);
for(ll i=1;i<=n;++i){
insert(root,1,dfs_clock,ind[i],c[i],1);
insert(root,1,dfs_clock,oud[i],c[i],-1);
}
watch(root,1,dfs_clock);
ll op,x,a;
while(m--){
read(op);
if(op == 1){
read(x);read(a);
modify(root,1,dfs_clock,ind[x],ind[x],a);
modify(root,1,dfs_clock,oud[x],oud[x],a);
}else if(op == 2){
read(x);read(a);
modify(root,1,dfs_clock,ind[x],oud[x],a);
}else if(op == 3){
read(x);
ll ans = query(root,1,dfs_clock,1,ind[x]);
printf("%lld\n",ans);
}
}
getchar();getchar();
return 0;
}

bzoj 4034: 树上操作 线段树的更多相关文章

  1. [BZOJ 4034] 树上操作

    Link: BZOJ 4034 传送门 Solution: 树剖模板题…… Code: #include <bits/stdc++.h> using namespace std; type ...

  2. BZOJ 4034 树上操作(树的欧拉序列+线段树)

    刷个清新的数据结构题爽一爽? 题意: 有一棵点数为 N 的树,以点 1 为根,且树点有边权.然后有 M 个 操作,分为三种: 操作 1 :把某个节点 x 的点权增加 a . 操作 2 :把某个节点 x ...

  3. BZOJ 4034 [HAOI2015]树上操作 线段树+树剖或dfs

    题意 直接照搬原题面 有一棵点数为 N 的树,以点 1 为根,且树点有边权.然后有 M 个 操作,分为三种: 操作 1 :把某个节点 x 的点权增加 a . 操作 2 :把某个节点 x 为根的子树中所 ...

  4. BZOJ 4034"树上操作"(DFS序+线段树)

    传送门 •题意 有一棵点数为 N 的树,以点 1 为根,且树点有边权. 然后有 M 个操作,分为三种: 操作 1 :把某个节点 x 的点权增加 a . 操作 2 :把某个节点 x 为根的子树中所有点的 ...

  5. bzoj 4034(DFS序+线段树)

    这个题多了一个操作难度直线上升,看完题解才会写 有一棵点数为 N 的树,以点 1 为根,且树点有边权.然后有 M 个操作,分为三种:操作 1 :把某个节点 x 的点权增加 a .操作 2 :把某个节点 ...

  6. cf1110F 离线+树上操作+线段树区间更新

    自己搞的算法超时了..但是思路没什么问题:用线段树维护每个点到叶子节点的距离即可 /* 线段树维护区间最小值,每次向下访问,就把访问到的点对应的区间段减去边权 到另一颗子树访问时,向上回溯时加上减去的 ...

  7. bzoj 2962 序列操作——线段树(卷积?)

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=2962 如果 _,_,_,…… 变成了 (_+k),(_+k),(_+k),…… ,计算就是在 ...

  8. bzoj 2962 序列操作 —— 线段树

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=2962 维护 sum[i] 表示选 i 个的乘积和,合并两个子树就枚举两边选多少,乘起来即可: ...

  9. [BZOJ3307] 雨天的尾巴(树上差分+线段树合并)

    [BZOJ3307] 雨天的尾巴(树上差分+线段树合并) 题面 给出一棵N个点的树,M次操作在链上加上某一种类别的物品,完成所有操作后,要求询问每个点上最多物品的类型. N, M≤100000 分析 ...

随机推荐

  1. pthon 基础 9.8 增加数据

    #/usr/bin/python #-*- coding:utf-8 -*- #@Time   :2017/11/24 2:59 #@Auther :liuzhenchuan #@File   :增加 ...

  2. TP的分页加查询

    1.查询显示数据库的内容 控制器里的内容 public function shouye() { $n = M("car"); $arr = $n->select(); $th ...

  3. EasyNVR无插件直播服务器软件览器低延时播放监控摄像头视频(EasyNVR播放FLV视频流)

    背景描述 EasyNVR的使用者应该都是清楚的了解到,EasyNVR一个强大的功能就是可以进行全平台的无插件直播.主要原因在于rtsp协议的视频流(默认是需要插件才可以播放的)经由EasyNVR处理可 ...

  4. 今天在网上查看了一个socket程序,运行的时候一直报错,经过队友解决?

    1.首先是问题代码ip_port = ('192.168.12.2',8001)2.上边的代码本身没有问题,但是必须经过修改自己本机的局域网IP地址才能顺利链接请参考上一篇blog的地址,查看本机的i ...

  5. Linux安装Nginx使用反向代理

    nginx的反向代理功能(自带了反向代理的功能,天生的二道贩子)1.实验环境准备准备2个服务器,都安装好nginx软件nginx1 192.168.13.79 作为web服务器 (理解为火车票售票点) ...

  6. pom.xml配置文件详解(转发)

    setting.xml主要用于配置maven的运行环境等一系列通用的属性,是全局级别的配置文件:而pom.xml主要描述了项目的maven坐标,依赖关系,开发者需要遵循的规则,缺陷管理系统,组织和li ...

  7. CHAR,TCHAR,WCHAR 三者的区别与转换

    #ifdef   UNICODE               typedef   wchar_t   TCHAR; #else               typedef   unsigned   c ...

  8. expr 数字操作

    expr 可以用于计算 [root@rhel6 script]# * * [root@rhel6 script]# 使用expr来判断输入的变量是否为整数, 注意这里的&表示  安静模式(没有 ...

  9. Git 远程仓库 git remote

    http://blog.csdn.net/s0228g0228/article/details/45368155 Git remote -v 查看现有远程仓库的地址url 三种方式都可以. 1. 修改 ...

  10. UOJ78 二分图最大匹配

    从前一个和谐的班级,有 nlnl 个是男生,有 nrnr 个是女生.编号分别为 1,…,nl1,…,nl 和 1,…,nr1,…,nr. 有若干个这样的条件:第 vv 个男生和第 uu 个女生愿意结为 ...