题目大意

有一棵点数为 N 的树,以点 1 为根,且树点有边权。然后有 M 个

操作,分为三种:

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

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

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

分析

真就是一见到这类题就得先写一次,发现错,再写一次

想清楚再写行不 -.-

方法1:树剖

方法2:入栈出栈序

入栈+,出栈 -

一个点x到根路径和,就是sum[1,in[x]]

如何区间修改呢

线段树上记录区间中 +的个数减去 -的个数

就是一次修改中权值总体要增加多少个delta

具体见代码

solution

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cctype>
#include <cmath>
#include <algorithm>
using namespace std;
typedef long long LL;
const int M=100007; inline int rd(){
int x=0;bool f=1;char c=getchar();
for(;!isdigit(c);c=getchar()) if(c=='-') f=0;
for(;isdigit(c);c=getchar()) x=x*10+c-48;
return f?x:-x;
} LL val[M];
int n,m;
int g[M],te;
struct edge{
int y,nxt;
}e[M<<1]; void addedge(int x,int y){
e[++te].y=y;e[te].nxt=g[x];g[x]=te;
} int st[M],ed[M],ty[M<<1],dd[M<<1],tdfn=0; void dfs(int x,int fa){
st[x]=++tdfn;
ty[tdfn]=1;
dd[tdfn]=val[x];
int p,y;
for(p=g[x];p;p=e[p].nxt)
if((y=e[p].y)!=fa) dfs(y,x);
ed[x]=++tdfn;
ty[tdfn]=-1;
dd[tdfn]=-val[x];
} struct seg{
LL sum,tag,sz;
}a[M<<3]; void pushup(int x){
a[x].sum=a[x<<1].sum+a[x<<1|1].sum;
} void totag(int x,LL d){
a[x].sum+=d*a[x].sz;
a[x].tag+=d;
} void pushdown(int x){
if(a[x].tag){
totag(x<<1,a[x].tag);
totag(x<<1|1,a[x].tag);
a[x].tag=0;
}
} void build(int x,int l,int r){
if(l==r){
a[x].sum=dd[l];
a[x].sz=ty[l];
a[x].tag=0;
return;
}
int mid=l+r>>1;
build(x<<1,l,mid);
build(x<<1|1,mid+1,r);
pushup(x);
a[x].sz=a[x<<1].sz+a[x<<1|1].sz;
} void add(int x,int l,int r,int tl,int tr,LL d){
if(tl<=l&&r<=tr){
totag(x,d);
return;
}
int mid=l+r>>1;
pushdown(x);
if(tl<=mid) add(x<<1,l,mid,tl,tr,d);
if(mid<tr) add(x<<1|1,mid+1,r,tl,tr,d);
pushup(x);
} LL get(int x,int l,int r,int tl,int tr){
if(tl<=l&&r<=tr) return a[x].sum;
int mid=l+r>>1;
pushdown(x);
LL res=0;
if(tl<=mid) res+=get(x<<1,l,mid,tl,tr);
if(mid<tr) res+=get(x<<1|1,mid+1,r,tl,tr);
return res;
} int main(){
int i,kd,x,y;
n=rd(); m=rd();
for(i=1;i<=n;i++) val[i]=rd();
for(i=1;i<n;i++){
x=rd(),y=rd();
addedge(x,y);
addedge(y,x);
} dfs(1,0); build(1,1,2*n); while(m--){
kd=rd();
if(kd==1){
x=rd(); y=rd();
add(1,1,2*n,st[x],st[x],y);
add(1,1,2*n,ed[x],ed[x],y);
}
else if(kd==2){
x=rd(); y=rd();
add(1,1,2*n,st[x],ed[x],y);
}
else{
x=rd();
printf("%lld\n",get(1,1,2*n,1,st[x]));
}
}
return 0;
}

bzoj 4034 [HAOI2015]树上操作 入栈出栈序+线段树 / 树剖 维护到根距离和的更多相关文章

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

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

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

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

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

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

  4. [BZOJ]4034: [HAOI2015]树上操作

    [HAOI2015]树上操作 传送门 题目大意:三个操作 1:a,b,c b节点权值+c 2:a,b,c 以b为根的子树节点权值全部+c 3:a,b 查询b到根路径的权值和. 题解:树链剖分 操作1 ...

  5. BZOJ 4034 [HAOI2015]树上操作(欧拉序+线段树)

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

  6. BZOJ 4034: [HAOI2015]树上操作 [欧拉序列 线段树]

    题意: 操作 1 :把某个节点 x 的点权增加 a . 操作 2 :把某个节点 x 为根的子树中所有点的点权都增加 a . 操作 3 :询问某个节点 x 到根的路径中所有点的点权和. 显然树链剖分可做 ...

  7. 洛谷 P3178 BZOJ 4034 [HAOI2015]树上操作

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

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

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

  9. bzoj 4034: [HAOI2015]树上操作——树链剖分

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

随机推荐

  1. Linux Cache 机制探究

    http://www.penglixun.com/tech/system/linux_cache_discovery.html

  2. tomcat - 自带日志的区分

    在tomcat 中,logs文件夹下会存放着一些tomcat自带的日志文件,其中有三种文件: 1 > localhost_access_log.2017-12-28 文件,它用来记录tomcat ...

  3. CentOs 6.5设置使用私钥登录关闭ssh的密码登录修改ssh默认端口

    使用SecureCRT工具创建RSA公钥和私钥 [选项]=>[会话选项] 然后在弹出对话框中选择[公钥]然后点击[属性]: 在弹出窗口中选中[使用会话公钥设置],点击[创建身份文件]按钮: 然后 ...

  4. crond定时操作 crontab

    * * * * *  分别表示 分钟  小时  日  月  星期(0-6) 30 17,28,19 * * *  或 30 17-19 * * *  在每天的17-19小时半点时刻执行 30 8-18 ...

  5. pandas修改列名

  6. .Net Task常见问题

    最近尝试使用一下Task,但是使用过程中因为API的不熟悉碰到了很多问题,不清楚什么时间来调用Task.Start(),具体该怎么使用等等. 如下所描述的Task.Start()方法均为实例方法. 1 ...

  7. javaweb通过接口来实现多个文件压缩和下载(包括单文件下载,多文件批量下载)

    原博客地址:https://blog.csdn.net/weixin_37766296/article/details/80044000 将多个文件压缩并下载下来:(绿色为修改原博客的位置) 注意:需 ...

  8. Ubuntu首次登入与在线求助man page总结

    1.为了避免瞬间断电造成的Linux系统的危害,建议做为服务器的Linux主机应该加上不断电系统来持续提供稳定的电力 2.默认的图形模式登入中,可以选择语系以及作业阶段.作业阶段为多种窗口管理员软件所 ...

  9. Selenium WebDriver-打开3个网址截图,文件夹用年月日命名,图片用当前时分秒命名

    import os import os.path import time from selenium import webdriver urls=["http://www.baidu.com ...

  10. 第二章 jquery的dom操作

    三个方面    dom核心,html-dom和css-dom 一. 1.dom core核心 document.getElementsByTagName("form")  获取表单 ...