洛谷P3178 [HAOI2015]树上操作(线段树)
题目描述
有一棵点数为 N 的树,以点 1 为根,且树点有边权。然后有 M 个操作,分为三种:操作 1 :把某个节点 x 的点权增加 a 。操作 2 :把某个节点 x 为根的子树中所有点的点权都增加 a 。操作 3 :询问某个节点 x 到根的路径中所有点的点权和。
输入输出格式
输入格式:
第一行包含两个整数 N, M 。表示点数和操作数。接下来一行 N 个整数,表示树中节点的初始权值。接下来 N-1 行每行两个正整数 from, to , 表示该树中存在一条边 (from, to) 。再接下来 M 行,每行分别表示一次操作。其中第一个数表示该操作的种类( 1-3 ) ,之后接这个操作的参数( x 或者 x a ) 。
输出格式:
对于每个询问操作,输出该询问的答案。答案之间用换行隔开。
输入输出样例
说明
对于 100% 的数据, N,M<=100000 ,且所有输入数据的绝对值都不
会超过 10^6 。
题解
不得不说大佬的思路真是非常厉害
我们考虑一下,对一个节点的单点修改会对它整棵子树的答案都产生影响,相当于给它的整个子树都加上一个值,也就是子树的答案都变化了$z$
然后考虑给以某个节点为根的子树增加权值,那么节点$y$增加的权值就是$dep[y]*z-(dep[x]-1)*z$,那么我们可以看成是$x$的子树中的每一个节点的答案都变化了$-(dep[x]-1)*z$,那么查询的时候只要记录下每一个节点的$z$值总和$a$,以及上面的变化总和$b$,那么答案就是$a*dep[y]+b$
区间修改,单点查询,只要用dfs序+线段树即可
ps:然后我抄看代码的时候有一个细节没有弄懂,为啥他每次pushdown的时候可以把$a,b$传给儿子之后自己清零。后来想了想发现因为是单点查询,节点都在最底端,所以上面的点清零对他们没有影响,因为他们的答案已经加上了影响,而且最底端的点不可能再pushdown下去,所以代码没问题,而且能防止上面的点的贡献重复加给下面的点
//minamoto
#include<bits/stdc++.h>
#define ll long long
using namespace std;
#define getc() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++)
char buf[<<],*p1=buf,*p2=buf;
inline int read(){
#define num ch-'0'
char ch;bool flag=;int res;
while(!isdigit(ch=getc()))
(ch=='-')&&(flag=true);
for(res=num;isdigit(ch=getc());res=res*+num);
(flag)&&(res=-res);
#undef num
return res;
}
char sr[<<],z[];int C=-,Z;
inline void Ot(){fwrite(sr,,C+,stdout),C=-;}
inline void print(ll x){
if(C><<)Ot();if(x<)sr[++C]=,x=-x;
while(z[++Z]=x%+,x/=);
while(sr[++C]=z[Z],--Z);sr[++C]='\n';
}
const int N=;
int ver[N<<],Next[N<<],head[N],sz[N],dfn[N],fa[N],tot,num;
ll a[N<<],b[N<<],val[N],dis[N];
int n,m;
inline void add(int u,int v){
ver[++tot]=v,Next[tot]=head[u],head[u]=tot;
ver[++tot]=u,Next[tot]=head[v],head[v]=tot;
}
void dfs(int u){
dis[u]=dis[fa[u]]+,dfn[u]=++num,sz[u]=;
for(int i=head[u];i;i=Next[i]){
int v=ver[i];
if(v!=fa[u]){
fa[v]=u,dfs(v),sz[u]+=sz[v];
}
}
}
inline void pushdown(int p){
a[p<<]+=a[p],a[p<<|]+=a[p];
b[p<<]+=b[p],b[p<<|]+=b[p];
a[p]=b[p]=;
}
void update(int p,int l,int r,int ql,int qr,ll x,ll y){
if(ql<=l&&qr>=r) return (void)(a[p]+=x,b[p]+=y);
pushdown(p);
int mid=l+r>>;
if(ql<=mid) update(p<<,l,mid,ql,qr,x,y);
if(qr>mid) update(p<<|,mid+,r,ql,qr,x,y);
}
ll query(int u,int x,int p,int l,int r){
if(l==r) return dis[u]*a[p]+b[p];
pushdown(p);
int mid=l+r>>;
if(x<=mid) return query(u,x,p<<,l,mid);
else return query(u,x,p<<|,mid+,r);
}
int main(){
n=read(),m=read();
for(int i=;i<=n;++i) val[i]=read();
for(int i=;i<n;++i){
int u=read(),v=read();add(u,v);
}
dfs();
for(int i=;i<=n;++i) update(,,n,dfn[i],dfn[i]+sz[i]-,,val[i]);
while(m--){
int opt=read(),x=read();
switch(opt){
case :{
int y=read();
update(,,n,dfn[x],dfn[x]+sz[x]-,,y);
break;
}
case :{
int y=read();
update(,,n,dfn[x],dfn[x]+sz[x]-,y,-(1ll*(dis[x]-)*y));
break;
}
case :{
print(query(x,dfn[x],,,n));
break;
}
}
}
Ot();
return ;
}
洛谷P3178 [HAOI2015]树上操作(线段树)的更多相关文章
- 洛谷P3178 [HAOI2015]树上操作 题解 树链剖分+线段树
题目链接:https://www.luogu.org/problem/P3178 这道题目是一道树链剖分的模板题. 但是在解决这道问题的同事刷新了我的两个认识: 第一个认识是:树链剖分不光可以处理链, ...
- 洛谷P3178 [HAOI2015]树上操作(dfs序+线段树)
P3178 [HAOI2015]树上操作 题目链接:https://www.luogu.org/problemnew/show/P3178 题目描述 有一棵点数为 N 的树,以点 1 为根,且树点有边 ...
- 洛谷P3178 [HAOI2015]树上操作
题目描述 有一棵点数为 N 的树,以点 1 为根,且树点有边权.然后有 M 个操作,分为三种:操作 1 :把某个节点 x 的点权增加 a .操作 2 :把某个节点 x 为根的子树中所有点的点权都增加 ...
- 洛谷 P3178 [HAOI2015]树上操作
题目描述 有一棵点数为 N 的树,以点 1 为根,且树点有边权.然后有 M 个操作,分为三种:操作 1 :把某个节点 x 的点权增加 a .操作 2 :把某个节点 x 为根的子树中所有点的点权都增加 ...
- 洛谷——P3178 [HAOI2015]树上操作
https://www.luogu.org/problem/show?pid=3178#sub 题目描述 有一棵点数为 N 的树,以点 1 为根,且树点有边权.然后有 M 个操作,分为三种:操作 1 ...
- BZOJ 4034 [HAOI2015]树上操作 线段树+树剖或dfs
题意 直接照搬原题面 有一棵点数为 N 的树,以点 1 为根,且树点有边权.然后有 M 个 操作,分为三种: 操作 1 :把某个节点 x 的点权增加 a . 操作 2 :把某个节点 x 为根的子树中所 ...
- 洛谷$P2572\ [SCOI2010]$ 序列操作 线段树/珂朵莉树
正解:线段树/珂朵莉树 解题报告: 传送门$w$ 本来是想写线段树的,,,然后神仙$tt$跟我港可以用珂朵莉所以决定顺便学下珂朵莉趴$QwQ$ 还是先写线段树做法$QwQ$? 操作一二三四都很$eas ...
- 洛谷 3178 [HAOI2015]树上操作
[题解] 就是个树链剖分的模板题. #include<cstdio> #include<algorithm> #include<cstring> #define L ...
- P3178 [HAOI2015]树上操作
P3178 [HAOI2015]树上操作 思路 板子嘛,其实我感觉树剖没啥脑子 就是debug 代码 #include <bits/stdc++.h> #define int long l ...
随机推荐
- SQL基础(1)
1.SQL简介 (1)什么是SQL? SQL指结构化查询语言 SQL使我们有能力访问数据库 SQL是一种 ANSI 的标准计算机语言 (2)SQL 能做什么? SQL面向数据库执行查询 SQL可从数据 ...
- 12-21C#电脑蓝屏效果(可以恶搞整人哦)、输入输出流(StreamReader/streamWriter)
一.winform电脑蓝屏效果 第一种方法:基本操作: 第一步:创建一个新的C#窗体“Form1”: 第二步:在设计窗口中,更改其属性: 1)text属性:将form1的text属性中的文字取消掉,然 ...
- 回调函数(callback)经典解答
著作权归作者所有.商业转载请联系作者获得授权,非商业转载请注明出处.作者:常溪玲链接:http://www.zhihu.com/question/19801131/answer/13005983来源: ...
- oracle -sqlplus 调用存储过程
sp.batsqlplus user/passwd/sid @.\sp.sql >sp.sqlexit; sp.sqlexex xxxx()quit;
- day17-jdbc 2.jdbc介绍
SQL是一种非过程性语言,只能写一条嘛,你写多条不行嘛.每个数据库都有自己的存储过程.你可以做编程,你可以写多条SQL语句把它放到一起.这就是存储过程.然后用的时候一调它就执行这个逻辑结构了.因为多条 ...
- eclipse格式化代码模板
<?xml version="1.0" encoding="UTF-8" standalone="no"?> <profi ...
- Contset Hunter 1102 高精度求卡特兰数
用递推的方式写的写挂了,而如果用组合数又不会高精度除法,偶然看到了别人的只用高精度乘低精度求组合数的方法,记录一下 #include<bits/stdc++.h> using namesp ...
- sql中的Alias怎么用
一直很奇怪,不知道为什么sql的Alias怎么用,上次看到ThinkPHP中的讲解,为什么数据库在用的时候有时候喜欢改个别名再用, 因为昨天去参加了公司的数据库开发工程师的笔试,今天就复习一下sql, ...
- (转)Linux网络协议栈(三)——网络设备(1)
网络设备(network device)是内核对网络适配器(硬件)的抽象与封装,并为各个协议实例提供统一的接口,它是硬件与内核的接口,它有两个特征:(1) 作为基于硬件的网络适配器与基于软件的协 ...
- 算法Sedgewick第四版-第1章基础-2.1Elementary Sortss-004希尔排序法(Shell Sort)
一.介绍 1.希尔排序的思路:希尔排序是插入排序的改进.当输入的数据,顺序是很乱时,插入排序会产生大量的交换元素的操作,比如array[n]的最小的元素在最后,则要经过n-1次交换才能排到第一位,因为 ...