题解 P3372 【【模板】线段树1 】(zkw)
看了一下题解里的zkw线段树,感觉讲的不是很清楚啊(可能有清楚的但是我没翻到,望大佬勿怪)。
决定自己写一篇。。。希望大家能看明白。。。
zkw线段树是一种优秀的非递归线段树,速度比普通线段树快两道三倍,同时代码量不大。
(当然,存在很多线段树可做zkw不可做的题)
zkw线段树的核心思路就是先修改叶子,然后从底向上沿着路径修改。
如果画一张图出来整个过程有点像逐渐两条交回在根节点的链。
注意:对于需要维护的区间[1,n],zkw线段树维护的实际上是[0,n+1]。
建树
inline void build(ll n){
bit=1;
while(bit<n+2)bit<<=1;
for(ll i=1;i<=n;++i)tree[bit+i]=a[i];
for(ll i=bit-1;i>=1;--i)tree[i]=tree[i<<1]+tree[i<<1|1],tag[i]=0;
}
bit表示的底层的大小,我们需要先预处理出这个全局变量。
然后我们就可以先把叶子的值全部读入。
读入之后就顺着叶子向上走,更新上面的节点。
这一段代码没有什么复杂的地方。
更新
inline void update(ll l,ll r,ll val){
ll s,t,ln=0,rn=0,x=1;
for(s=bit+l-1,t=bit+r+1;s^t^1;s>>=1,t>>=1,x<<=1){
tree[s]+=val*ln,tree[t]+=val*rn;
if(~s&1)tag[s^1]+=val,tree[s^1]+=val*x,ln+=x;
if(t&1)tag[t^1]+=val,tree[t^1]+=val*x,rn+=x;
}
for(;s;s>>=1,t>>=1)tree[s]+=val*ln,tree[t]+=val*rn;
}
更新操作稍微比建树复杂一点。
s和t就是先前提到的两条链,当然准确地说,它们的轨迹才是那两条链。
ln,rn表示的是当前节点的长度(也就是s,t的长度)。
x表示的是s和t中间这一坨的长度。
然后也是一样的自底向上,每一次先更新两边,然后再判断该更新左儿子还是右儿子。
查询
inline ll query(ll l,ll r){
ll s,t,ln=0,rn=0,x=1,ans=0;
for(s=bit+l-1,t=bit+r+1;s^t^1;s>>=1,t>>=1,x<<=1){
if(tag[s])ans+=tag[s]*ln;
if(tag[t])ans+=tag[t]*rn;
if(~s&1)ans+=tree[s^1],ln+=x;
if(t&1)ans+=tree[t^1],rn+=x;
}
for(;s;s>>=1,t>>=1)ans+=tag[s]*ln,ans+=tag[t]*rn;
return ans;
}
查询操作和更新一样,没什么好讲的。
不开O2跑了511ms,比普通线段树的760+ms快很多(可能是我写丑了)
完整代码如下:
#include<bits/stdc++.h>
using namespace std;
typedef unsigned long long ll;
const ll N=100100;
ll n,m;
ll op,x,y,z;
ll a[N];
ll bit;
ll tree[N<<2],tag[N<<2];
inline void build(ll n){
bit=1;
while(bit<n+2)bit<<=1;
for(ll i=1;i<=n;++i)tree[bit+i]=a[i];
for(ll i=bit-1;i>=1;--i)tree[i]=tree[i<<1]+tree[i<<1|1],tag[i]=0;
}
inline void update(ll l,ll r,ll val){
ll s,t,ln=0,rn=0,x=1;
for(s=bit+l-1,t=bit+r+1;s^t^1;s>>=1,t>>=1,x<<=1){
tree[s]+=val*ln,tree[t]+=val*rn;
if(~s&1)tag[s^1]+=val,tree[s^1]+=val*x,ln+=x;
if(t&1)tag[t^1]+=val,tree[t^1]+=val*x,rn+=x;
}
for(;s;s>>=1,t>>=1)tree[s]+=val*ln,tree[t]+=val*rn;
}
inline ll query(ll l,ll r){
ll s,t,ln=0,rn=0,x=1,ans=0;
for(s=bit+l-1,t=bit+r+1;s^t^1;s>>=1,t>>=1,x<<=1){
if(tag[s])ans+=tag[s]*ln;
if(tag[t])ans+=tag[t]*rn;
if(~s&1)ans+=tree[s^1],ln+=x;
if(t&1)ans+=tree[t^1],rn+=x;
}
for(;s;s>>=1,t>>=1)ans+=tag[s]*ln,ans+=tag[t]*rn;
return ans;
}
int main(){
scanf("%lld%lld",&n,&m);
for(ll i=1;i<=n;++i)scanf("%lld",&a[i]);
build(n);
while(m--){
scanf("%lld%lld%lld",&op,&x,&y);
if(op==1)scanf("%lld",&z),update(x,y,z);
else cout<<query(x,y)<<endl;
}
}
题解 P3372 【【模板】线段树1 】(zkw)的更多相关文章
- hdu 1754 I Hate It (模板线段树)
http://acm.hdu.edu.cn/showproblem.php?pid=1754 I Hate It Time Limit: 9000/3000 MS (Java/Others) M ...
- 洛谷P3373 [模板]线段树 2(区间增减.乘 区间求和)
To 洛谷.3373 [模板]线段树2 题目描述 如题,已知一个数列,你需要进行下面两种操作: 1.将某区间每一个数加上x 2.将某区间每一个数乘上x 3.求出某区间每一个数的和 输入输出格式 输入格 ...
- 【线段树】【P3372】模板-线段树
百度百科 Definition&Solution 线段树是一种log级别的树形结构,可以处理区间修改以及区间查询问题.期望情况下,复杂度为O(nlogn). 核心思想见百度百科,线段树即将每个 ...
- hdu3966 树链剖分点权模板+线段树区间更新/树状数组区间更新单点查询
点权树的模板题,另外发现树状数组也是可以区间更新的.. 注意在对链进行操作时方向不要搞错 线段树版本 #include<bits/stdc++.h> using namespace std ...
- 线段树和zkw线段树
作者作为一个蒟蒻,也是最近才自学了线段树,不对的地方欢迎大佬们评论,但是不要喷谢谢 好啦,我们就开始说说线段树吧 线段树是个支持区间操作和查询的东东,平时的话还是蛮实用的 下面以最基本的区间加以及查询 ...
- [NOIP10.6模拟赛]2.equation题解--DFS序+线段树
题目链接: 咕 闲扯: 终于在集训中敲出正解(虽然与正解不完全相同),开心QAQ 首先比较巧,这题是\(Ebola\)出的一场模拟赛的一道题的树上强化版,当时还口胡出了那题的题解 然而考场上只得了86 ...
- 算法模板——线段树6(二维线段树:区域加法+区域求和)(求助phile)
实现功能——对于一个N×M的方格,1:输入一个区域,将此区域全部值作加法:2:输入一个区域,求此区域全部值的和 其实和一维线段树同理,只是不知道为什么速度比想象的慢那么多,求解释...@acphile ...
- 【题解】Journeys(线段树优化连边)
[#3073. Pa2011]Journeys (线段树优化连边) 这张图太直观了,直接讲透了线段树优化连边的原理和正确性. 考虑建立两颗线段树,一颗是外向树,一颗是内向树,相当于网络流建模一样,我们 ...
- Gorgeous Sequence 题解 (小清新线段树)
这道题被学长称为“科幻题” 题面 事实上,并不是做法科幻,而是“为什么能这么做?”的解释非常科幻 换句话说,复杂度分析灰常诡异以至于吉如一大佬当场吃书 线段树维护的量:区间和sum,区间最大值max1 ...
- 洛谷题解P4314CPU监控--线段树
题目链接 https://www.luogu.org/problemnew/show/P4314 https://www.lydsy.com/JudgeOnline/problem.php?id=30 ...
随机推荐
- [USACO18JAN] Cow at Large G (dfs)
题目大意:有一只狐狸从给定的S点开始逃跑(出发),向叶节点移动以逃离这棵树,叶节点可能出现农民去抓捕狐狸,当农民和狐狸出现在同一个节点的时候,狐狸会被抓住,农民和狐狸移动速度相同,求抓捕狐狸所需要的最 ...
- python3 将两个列表生成一个字典
需求: 存在两个list如下 list1 = ["one", "two", "three"] list2 = ["1", ...
- [luogu] P4040 [AHOI2014/JSOI2014]宅男计划(贪心)
P4040 [AHOI2014/JSOI2014]宅男计划 题目背景 自从迷上了拼图,JYY就变成了个彻底的宅男.为了解决温饱问题,JYY不得不依靠叫外卖来维持生计. 题目描述 外卖店一共有N种食物, ...
- [CSS3] The picture element
<picture> <source media="(min-width: 1000px)" srcset="kookaburra_large_1x.jp ...
- 对Java、C#转学swift的提醒:学习swift首先要突破心理障碍。
网上非常多都说swift是一门新手友好的语言. 但以我当年从Java转学Ruby的经验,swift对于从Java.C#转来的程序猿实际并不友好.原因就在于原来总有一种错觉:一个语言最重要的就是严谨,而 ...
- python写个简单的文件上传是有多难,要么那么复杂,要么各种,,,老子来写个简单的
def upload(url,params): ''' 上传文件到server,不适合大文件 @params url 你懂的 @params {"action":"xxx ...
- 显示解析svg
g公司代码显示svg: SVGParserRenderer drawable = new SVGParserRenderer(context, String svgContent); String s ...
- bzoj1022: [SHOI2008]小约翰的游戏John(博弈SG-nim游戏)
1022: [SHOI2008]小约翰的游戏John 题目:传送门 题目大意: 一道反nim游戏,即给出n堆石子,每次可以取完任意一堆或一堆中的若干个(至少取1),最后一个取的LOSE 题解: 一道 ...
- [jzoj 6087] [GDOI2019模拟2019.3.26] 获取名额 解题报告 (泰勒展开+RMQ+精度)
题目链接: https://jzoj.net/senior/#main/show/6087 题目: 题解: 只需要统计$\prod_{i=l}^r (1-\frac{a_i}{x})$ =$exp(\ ...
- 将枚举存入map集合
遍历枚举存入集合: Map<String,Object> deptLevel = new HashMap<>(); for(OrgBussinessEnum orgBussin ...