题解 P3372 【【模板】线段树1 】
看了一下题解里的zkw线段树,感觉讲的不是很清楚啊(可能有清楚的但是我没翻到,望大佬勿怪)。
决定自己写一篇。。。希望大家能看明白。。。
zkw线段树是一种优秀的非递归线段树,速度比普通线段树快两道三倍,同时代码量不大。
(当然,存在很多线段树可做zkw不可做的题)
zkw线段树的核心思路就是先修改叶子,然后从底向上沿着路径修改。
如果画一张图出来整个过程有点像逐渐两条交回在根节点的链。
注意:对于需要维护的区间$[1,n]$,zkw线段树维护的实际上是$[0,n+1]$。
建树
inline void build(ll n){
bit=;
while(bit<n+)bit<<=;
for(ll i=;i<=n;++i)tree[bit+i]=a[i];
for(ll i=bit-;i>=;--i)tree[i]=tree[i<<]+tree[i<<|],tag[i]=;
}
bit表示的底层的大小,我们需要先预处理出这个全局变量。
然后我们就可以先把叶子的值全部读入。
读入之后就顺着叶子向上走,更新上面的节点。
这一段代码没有什么复杂的地方。
更新
inline void update(ll l,ll r,ll val){
ll s,t,ln=,rn=,x=;
for(s=bit+l-,t=bit+r+;s^t^;s>>=,t>>=,x<<=){
tree[s]+=val*ln,tree[t]+=val*rn;
if(~s&)tag[s^]+=val,tree[s^]+=val*x,ln+=x;
if(t&)tag[t^]+=val,tree[t^]+=val*x,rn+=x;
}
for(;s;s>>=,t>>=)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=,rn=,x=,ans=;
for(s=bit+l-,t=bit+r+;s^t^;s>>=,t>>=,x<<=){
if(tag[s])ans+=tag[s]*ln;
if(tag[t])ans+=tag[t]*rn;
if(~s&)ans+=tree[s^],ln+=x;
if(t&)ans+=tree[t^],rn+=x;
}
for(;s;s>>=,t>>=)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=;
ll n,m;
ll op,x,y,z;
ll a[N];
ll bit;
ll tree[N<<],tag[N<<];
inline void build(ll n){
bit=;
while(bit<n+)bit<<=;
for(ll i=;i<=n;++i)tree[bit+i]=a[i];
for(ll i=bit-;i>=;--i)tree[i]=tree[i<<]+tree[i<<|],tag[i]=;
}
inline void update(ll l,ll r,ll val){
ll s,t,ln=,rn=,x=;
for(s=bit+l-,t=bit+r+;s^t^;s>>=,t>>=,x<<=){
tree[s]+=val*ln,tree[t]+=val*rn;
if(~s&)tag[s^]+=val,tree[s^]+=val*x,ln+=x;
if(t&)tag[t^]+=val,tree[t^]+=val*x,rn+=x;
}
for(;s;s>>=,t>>=)tree[s]+=val*ln,tree[t]+=val*rn;
}
inline ll query(ll l,ll r){
ll s,t,ln=,rn=,x=,ans=;
for(s=bit+l-,t=bit+r+;s^t^;s>>=,t>>=,x<<=){
if(tag[s])ans+=tag[s]*ln;
if(tag[t])ans+=tag[t]*rn;
if(~s&)ans+=tree[s^],ln+=x;
if(t&)ans+=tree[t^],rn+=x;
}
for(;s;s>>=,t>>=)ans+=tag[s]*ln,ans+=tag[t]*rn;
return ans;
}
int main(){
scanf("%lld%lld",&n,&m);
for(ll i=;i<=n;++i)scanf("%lld",&a[i]);
build(n);
while(m--){
scanf("%lld%lld%lld",&op,&x,&y);
if(op==)scanf("%lld",&z),update(x,y,z);
else cout<<query(x,y)<<endl;
}
}
题解 P3372 【【模板】线段树1 】的更多相关文章
- 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 ...
- [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 ...
- [NOI2016]区间 题解(决策单调性+线段树优化)
4653: [Noi2016]区间 Time Limit: 60 Sec Memory Limit: 256 MBSubmit: 1593 Solved: 869[Submit][Status][ ...
随机推荐
- ASP.NET 让ajax请求webform后台方法
$.ajax({ type: "POST", url: ".aspx/getSubjectDirection", data: JSON.stringify({ ...
- QNX多线程同步之Barrier(屏障)
之前和大家介绍过QNX上的线程同步方法metux和semophore,通过这两种方法可以对一个或者几个资源进行加锁,避免资源使用上的冲突.在另一种情况下,某个线程需要在其它线程完成工作后才继续执行,这 ...
- (2016北京集训十三)【xsy1533】mushroom - bitset
题解: 神题...我看到的时候直接吓懵了... 这是一道STL题...否则可能要写可持久化ETT或者可持久化Toptree? 用bitset来维护每个蘑菇上哪里有杂草,那么 对于操作1和操作2:可以预 ...
- Linux Shell脚本编程-信号捕获
bash编程的信号捕获: kill -l 显示当前系统可用信号(trap -l) 获取帮助:man 7 single 常用信号: 1) SIGHUP 无须重启进程而让其重读配置文件 2) SI ...
- mariadb 视图 事务 索引 外键
视图 对于复杂的查询,在多个地方被使用,如果需求发生了改变,需要更改sql语句,则需要在多个地方进行修改,维护起来非常麻烦 假如因为某种需求,需要将user拆房表usera和表userb,该两张表 ...
- thymeleaf 常用标签
1.th:field th:field="*{user.sex}" 此标签会自动填充数据,比如用户的性别 user.sex 如果不为空,则会自动勾选上 2.th:each=&qu ...
- ORACLE数据库字符集处理
简介: ORACLE数据库字符集,即Oracle全球化支持(Globalization Support),或即国家语言支持(NLS)其作用是用本国语言和格式来存储.处理和检索数据.利用全球化支持,OR ...
- 杭电OJ(HDU)-ACMSteps-Chapter Two-《An Easy Task》《Buildings》《decimal system》《Vowel Counting》
http://acm.hdu.edu.cn/game/entry/problem/list.php?chapterid=1§ionid=2 1.2.5 #include<stdio.h> ...
- 设计模式-策略模式(Go语言描写叙述)
好久没有更新博客了.近期也是在忙着充电,今天这篇博客開始,我们来了解一下设计模式. 设计模式 那什么是设计模式呢?首先来看看我从百科上copy下来的概念吧. 设计模式/软件设计模式(Design pa ...
- android:为TextView加入样式——下划线,颜色,设置链接样式及前背景色
实现下划线及颜色设置: public class AtActivity extends Activity { LinearLayout ll; /** Called when the acti ...