luogu 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 ) 。
输出格式
对于每个询问操作,输出该询问的答案。答案之间用换行隔开。
输入输出样例
5 5 1 2 3 4 5 1 2 1 4 2 3 2 5 3 3 1 2 1 3 5 2 1 2 3 3
6 9 13
说明/提示
对于 100% 的数据, N,M<=100000 ,且所有输入数据的绝对值都不会超过 10^6 。
分析
- 首先,我们要知道dfs序
- 就是一颗树进出栈的顺序
- 然后我们记录下他们的时间戳
- 就知道他们的左右子树在哪个区间
- 然后用线段树维护
- 还有一个重要的点是
- 我们可以发现1-x点就是x进栈的前缀
- 考虑如何维护线段树
- 首先我们是有x和-x的,我们要一个前缀数组搞出区间正x的个数
- 对于第一个修改x+=x -x+=-x就好了
- 然后主要区间加一定打lazy
- lazy的return 是如果数在区间里面的
- 然后还有
if (a<=mid) ans+=find(k<<1,a,b);
if (b>=mid+1) ans+=find(k<<1|1,a,b); 别忘了
代码
1 #include<iostream> 2 #include<cstdio> 3 #define ll long long 4 using namespace std; 5 ll a[500001]; 6 struct sb 7 { 8 ll l,r,sum,bz,add; 9 }t[2*200001]; 10 ll id[500001],num,le[500001],ri[500001],vis[500001],ss[500001]; 11 struct node 12 { 13 ll to,nx; 14 }g[2*200010]; 15 ll list[2*200010],cnt; 16 void add(ll x,ll y) 17 { 18 g[++cnt].to=y; g[cnt].nx=list[x]; list[x]=cnt; 19 g[++cnt].to=x; g[cnt].nx=list[y]; list[y]=cnt; 20 } 21 ll val[500001],v,flag[500001]; 22 inline ll read(){ 23 ll x=0,f=1; 24 char ch=getchar(); 25 while(ch<'0'||ch>'9'){ 26 if(ch=='-') 27 f=-1; 28 ch=getchar(); 29 } 30 while(ch>='0'&&ch<='9'){ 31 x=(x<<1)+(x<<3)+(ch^48); 32 ch=getchar(); 33 } 34 return x*f; 35 } 36 void dfs(ll x) 37 { 38 vis[x]=1; 39 id[x]=++num; 40 val[num]=a[x]; 41 flag[num]=1; 42 le[x]=num; 43 for (int i=list[x];i;i=g[i].nx) 44 { 45 ll y=g[i].to; 46 if (!vis[y]) 47 dfs(y); 48 } 49 ri[x]=++num; 50 val[num]=-a[x]; 51 flag[num]=-1; 52 } 53 void build(ll k,ll a,ll b) 54 { 55 t[k].l=a; t[k].r=b; 56 if (a==b) 57 { 58 t[k].sum=val[a]; 59 t[k].bz=flag[a]; 60 return; 61 } 62 ll mid=a+b>>1; 63 build(k<<1,a,mid); 64 build(k<<1|1,mid+1,b); 65 t[k].sum=t[k<<1].sum+t[k<<1|1].sum; 66 t[k].bz=t[k<<1].bz+t[k<<1|1].bz; 67 } 68 void change(ll k,ll mb,ll z) 69 { 70 t[k].sum+=z; 71 if (t[k].l==t[k].r) return; 72 ll mid=t[k].l+t[k].r>>1; 73 if (mb<=mid) change(k<<1,mb,z); 74 else change(k<<1|1,mb,z); 75 } 76 void lazy(ll k,ll a,ll b,ll m) 77 { 78 if (t[k].add!=0) 79 { 80 t[k<<1].add+=t[k].add; 81 t[k<<1|1].add+=t[k].add; 82 t[k<<1].sum=t[k<<1].sum+t[k].add*(ss[m]-ss[a-1]); 83 t[k<<1|1].sum=t[k<<1|1].sum+t[k].add*(ss[b]-ss[m]); 84 t[k].add=0; 85 } 86 } 87 void change2(ll k,ll a,ll b,ll z) 88 { 89 if (a<=t[k].l&&b>=t[k].r) 90 { 91 t[k].add+=z; 92 t[k].sum=t[k].sum+z*(ss[t[k].r]-ss[t[k].l-1]); 93 return; 94 } 95 ll mid=(t[k].l+t[k].r)>>1; 96 lazy(k,t[k].l,t[k].r,mid); 97 if (a<=mid) change2(k<<1,a,b,z); 98 if (b>=mid+1) change2(k<<1|1,a,b,z); 99 t[k].sum=t[k<<1].sum+t[k<<1|1].sum; 100 } 101 ll find(ll k,ll a,ll b) 102 { 103 if (t[k].l>=a&&t[k].r<=b) 104 return t[k].sum; 105 ll mid=t[k].l+t[k].r>>1; 106 ll ans=0; 107 lazy(k,t[k].l,t[k].r,mid); 108 if (a<=mid) ans+=find(k<<1,a,b); 109 if (b>=mid+1) ans+=find(k<<1|1,a,b); 110 return ans; 111 } 112 int main () 113 { 114 ll n,m; 115 n=read(); m=read(); 116 for (int i=1;i<=n;i++) 117 a[i]=read(); 118 for (int i=1,x,y;i<=n-1;i++) 119 { 120 x=read(); y=read(); 121 add(x,y); 122 } 123 dfs(1); 124 for (int i=1;i<=num;i++) 125 ss[i]=ss[i-1]+flag[i]; 126 build(1,1,2*n); 127 for (int i=1,op,x,y;i<=m;i++) 128 { 129 op=read(); 130 if (op==1) 131 { 132 x=read(); y=read(); 133 change(1,le[x],y); 134 change(1,ri[x],-y); 135 } 136 if (op==2) 137 { 138 x=read(); y=read(); 139 change2(1,le[x],ri[x],y); 140 } 141 if (op==3) 142 { 143 x=read(); 144 printf("%lld\n",find(1,1,le[x])); 145 } 146 } 147 }
转载于:https://www.cnblogs.com/zjzjzj/p/11379377.html
luogu P3178 [HAOI2015]树上操作相关推荐
- P3178 [HAOI2015]树上操作
P3178 [HAOI2015]树上操作 题意: 题解: 这已经是很裸的树链剖分了... 直接套模板 代码: #include<cmath> #include<cstdio> ...
- Luogu P3177 [HAOI2015] 树上染色(树上背包)
整理的算法模板合集: ACM模板 点我看算法全家桶系列!!! 实际上是一个全新的精炼模板整合计划 Luogu P3177 [HAOI2015] 树上染色 有一棵点数为 NNN 的树,树边有边权.给你一 ...
- BZOJ 4043 [HAOI2015]树上操作 dfs序 线段树
$ \Rightarrow $ 戳我进BZOJ原题 $ \Rightarrow $ 戳我进洛谷原题 [HAOI2015]树上操作 Time Limit: 10 Sec Memory Limit: 25 ...
- bzoj 4034: [HAOI2015]树上操作(树链剖分+线段树区间更新)
4034: [HAOI2015]树上操作 Time Limit: 10 Sec Memory Limit: 256 MB Submit: 4981 Solved: 1603 [Submit][St ...
- [HAOI2015]树上操作
题目大意: 给你一棵n个点的树,以1为根,每个点都有一个点权,要求进行如下操作: 1.将x这个点的点权加上a: 2.将以x这个点为根的子树中每个点的点权加上a: 3.查询从x到根的路径的点权和. 思路 ...
- bzoj4034: [HAOI2015]树上操作
这题其实就是树剖裸题啊. 然后毒瘤选手由于上题树剖被卡到哭所以选择dfs序+树状数组. 不得不说简单的算法做出来更加难思考.然后网上的dalao们都一笔带过净说什么用两个树状数组维护就可以啦. 经过大 ...
- [BZOJ 4034][HAOI2015]树上操作(欧拉序列+线段树)
Description 有一棵点数为 N 的树,以点 1 为根,且树点有边权.然后有 M 个 操作,分为三种: 操作 1 :把某个节点 x 的点权增加 a . 操作 2 :把某个节点 x 为根的子树中 ...
- 省选专练HAOI2015树上操作
题如其名 树链剖分板子题 #include<bits/stdc++.h> using namespace std; #define lc (p<<1) #define rc ( ...
- [BZOJ4033][HAOI2015]树上染色
4033: [HAOI2015]树上染色 Time Limit: 10 Sec Memory Limit: 256 MB Submit: 2108 Solved: 901 [Submit][Sta ...
最新文章
- javascript数组降维_Javascript实现的数组降维——维度不同,怎么谈恋爱
- 比学习新技术更重要的是思维的改变
- android学习笔记:数据库存储
- Windows端口占用情况?
- bzoj 2330 糖果
- 随想录(fatfs的学习)
- 按照这个步骤来刷题,迷茫的你两个月亦能成为王者
- Git 协同开发流程
- Android 常用adb shell 命令
- spring中这些开发技巧真的太diao了
- EasyUI后台管理系统
- jscpd--前端代码重复率检测
- 篮球的各个位置的职能!!!
- offer比较:华为云核心网产品线和作业帮 都是开发
- python虚拟机:pvm
- SAP FICO 付款及清账解析
- SM-G9008V Root,google框架安装 设置开发者模式
- hdu1151Air Raid poj2594Treasure Exploration题解
- 【图像压缩】香农熵和差分进化算法多级图像阈值图像压缩【含Matlab源码 2035期】
- 怎么能学会做买卖步骤是什么(想做买卖赚钱应该先从什么做起)