①对于要求的输出,须要维护哪些信息(线段树节点里要存什么)?
②这些信息是否能够直接获得?
③若是不能,须要维护哪些信息来间接得到?node
两件事:由上而下干什么? 由下而上干什么?
由上而下的过程——初始化
由下而上的过程——合并区间信息
从上往下跑一圈又必需要倒回去的算法——递归。ios
那么就是递归实现的喽。git
理论上是2n-1的空间,可是你递归创建的时候当前节点为r
,那么左右孩子分别是2r,2r+1,此时编译器并不知道递归已结束,
由于你的结束条件是在递归以前的,因此编译器会认为下标访问出错,也就是空间开小了,
应该再开大2倍。有时候可能你发现开2,3倍的空间也能够AC,那只是由于测试数据并无那么大。算法
主要的思路就是递归加二分
看看代码吧(~~怀念那学长看着我打代码,强行改我码风的日子)测试
void build(ll l,ll r,ll rt) { t[rt].len = r - l + 1; if(l == r) { t[rt].sum = read(); return; } ll m = (l + r) >> 1; build(l, m, lson); build(m + 1, r ,rson); pushup(rt); }
知道二分与递归以后,单点查询那不就成了一个,二分求解的过程了嘛ui
void ask(int k) { if(tree[k].l==tree[k].r) //当前结点的左右端点相等,那么说明是叶子节点,是最终答案 { ans=tree[k].w; return ; } int m=(tree[k].l+tree[k].r)/2; // 二分查找 if(x<=m) ask(k*2); else ask(k*2+1); }
与单点查询没有什么区别,就是加了修改操做
还有一个回溯的过程this
void add(int k) { if(tree[k].l==tree[k].r)//找到目标位置 { tree[k].w+=y; return; } int m=(tree[k].l+tree[k].r)/2; if(x<=m) add(k*2); else add(k*2+1); tree[k].w=tree[k*2].w+tree[k*2+1].w;//全部包含结点k的结点状态更新 }
由于线段树的时候,有一些节点虽然咱们下放了值了,也加上了,可是咱们并无用到这个地方
那么咱们能够如今查询到的地方打上一个lazy标记(称为懒标记),而后每次查到这里的时候
就将当前的区间维护的值,与lazy标记处理一下就行了,这样咱们就没有必要再向下跑到叶子节点
而后在合并区间信息了,很麻烦,也很慢...spa
当他区间修改的时候,无非就是三种状况code
like this
blog
like this
like this
看一下代码吧
void updata(ll L,ll R,ll c,ll l,ll r,ll rt){ if(L <= l && r <= R){ t[rt].sum += t[rt].len * c; t[rt].lazy += c; return ; } pushdown(rt); ll m = (l + r) >> 1; if(L <= m) updata(L,R,c,l,m,lson); if(R > m) updata(L,R,c,m + 1,r,rson); pushup(rt); }
ll query(ll L,ll R,ll l,ll r,ll rt){ if(L <= l && r <= R) return t[rt].sum; pushdown(rt); ll m = (l + r) >> 1,ans=0; if(L <= m) ans+=query(L, R, l, m, lson); if(R > m) ans+=query(L, R, m + 1, r, rson); return ans; }
最后合并总的代码(由于单点查询与单点修改能够仿照区间查询与区间修改上来我就不放了)
#include<iostream> #include<cmath> #include<cstring> #include<cstdio> #include<algorithm> #include<map> #include<set> #include<vector> #include<string> #define ll long long #define N 1000010 #define lson rt << 1 #define rson rt << 1 | 1 using namespace std; ll n,m,rt; struct node { ll sum,lazy,len; } t[N << 2 | 1]; ll read() { ll s=0,f=0; char ch=getchar(); while(!isdigit(ch)) f|=(ch=='-'),ch=getchar(); while(isdigit(ch)) s=s*10+(ch^48),ch=getchar(); return f?-s:s; } void build(ll l,ll r,ll rt); void pushup(ll rt); void pushdown(ll rt); void updata(ll L,ll R,ll c,ll l,ll r,ll rt); ll query(ll L,ll R,ll l,ll r,ll rt); int main() { n = read(), m = read(); build(1,n,1); for(ll i = 1, opt, l, r, k; i <= m; i++){ opt = read(),l = read(),r = read(); if(opt == 1){k = read();updata(l,r,k,1,n,1);} else printf("%lld\n",query(l,r,1,n,1)); } return 0; } void build(ll l,ll r,ll rt) { t[rt].len = r - l + 1; if(l == r) { t[rt].sum = read(); return; } ll m = (l + r) >> 1; build(l, m, lson); build(m + 1, r ,rson); pushup(rt); } void pushup(ll rt) { t[rt].sum = t[lson].sum + t[rson].sum; } void pushdown(ll rt) { if(t[rt].lazy) { t[lson].lazy += t[rt].lazy; t[rson].lazy += t[rt].lazy; t[lson].sum += t[lson].len * t[rt].lazy; t[rson].sum += t[rson].len * t[rt].lazy; t[rt].lazy = 0; } } void updata(ll L,ll R,ll c,ll l,ll r,ll rt){ if(L <= l && r <= R){ t[rt].sum += t[rt].len * c; t[rt].lazy += c; return ; } pushdown(rt); ll m = (l + r) >> 1; if(L <= m) updata(L,R,c,l,m,lson); if(R > m) updata(L,R,c,m + 1,r,rson); pushup(rt); } ll query(ll L,ll R,ll l,ll r,ll rt){ if(L <= l && r <= R) return t[rt].sum; pushdown(rt); ll m = (l + r) >> 1,ans=0; if(L <= m) ans+=query(L, R, l, m, lson); if(R > m) ans+=query(L, R, m + 1, r, rson); return ans; }