基础的线段树就是去构建一个树,这个树符合二分,每个节点p的子节点是2*p,2*p+1。。。
因为1-2-4-8-。。。。1节点2,3。2个,然后下面节点就是4567,4个正好首节点大小个。。多巧。。。
然后维护这个树。当然可以实时更新整个树,但是时间复杂度大,所以我们使用懒标记。
如果改变的区域包含了一个大块,我们直接只更新大块的值并打上标记 (下面一样的递归办法) ,并在用到时把堆积的懒标记下传
在询问时,判断范围,如果在范围内,直接就是最大范围的值,如果不在,就取1节点的两个二分区间,比较一下大小,如果两边都有就是都有,往下去一直找。。比如1-16的大区间。我给个5-11改变;往下走,发现5-8这个直接就是一个,9,10是一个,11是一个。到此推完
#include<bits/stdc++.h>
using namespace std;
const int ma=100010;
long long a[ma+2];
struct tree{
int l,r;
long long pr,add;
}t[4*ma+2];
void bulid(int p,int l,int r){
t[p].l=l;t[p].r=r;
if(l==r){
t[p].pr=a[l];
return;
}
int mid=l+r>>1;
bulid(p*2,l,mid);
bulid(p*2+1,mid+1,r);
t[p].pr=t[p*2].pr+t[p*2+1].pr;
}
void sp(int p){
if(t[p].add){
t[p*2].pr+=t[p].add*(t[p*2].r-t[p*2].l+1);
t[p*2+1].pr+=t[p].add*(t[p*2+1].r-t[p*2+1].l+1);
t[p*2].add+=t[p].add;
t[p*2+1].add+=t[p].add;
t[p].add=0;
}
}
void change(int p,int x,int y,long long z){
if(x<=t[p].l && y>=t[p].r){
t[p].pr+=(long long)z*(t[p].r-t[p].l+1);
t[p].add+=z;
return;
}
sp(p);
int mid=t[p].l+t[p].r>>1;
if(x<=mid) change(p*2,x,y,z);
if(y>mid) change(p*2+1,x,y,z);
t[p].pr=t[p*2].pr+t[p*2+1].pr;
}
long long ask(int p,int x,int y){
if(x<=t[p].l && y>=t[p].r) return t[p].pr;
sp(p);
int mid=t[p].l+t[p].r>>1;
long long ans=0;
if(x<=mid) ans+=ask(p*2,x,y);
if(y>mid) ans+=ask(p*2+1,x,y);
return ans;
}
int main(){
ios_base::sync_with_stdio(false);
cin.tie(nullptr);
int n,m;
cin>>n>>m;
for(int i=1;i<=n;i++)
cin>>a[i];
bulid(1,1,n);
for(int i=1;i<=m;i++)
{
int q,x,y;
long long z;
cin>>q;
if(q==1){
cin>>x>>y>>z;
change(1,x,y,z);
}
else {
cin>>x>>y;
cout<<ask(1,x,y)<<endl;
}
}
return 0;
}
有非常多的细节,调试好久。。。注意该开long long 的地方
//题解 P3372 【【模板】线段树 1】 - 洛谷专栏(留给我自己看的
搞清楚乘法加法关系即可,每一个加法tag都实时在乘法时被乘。。。。参考数学原理想想就懂了
#include<bits/stdc++.h>
using namespace std;
const int ma=100010;
long long a[ma+2];
int h;
struct tree{
int l,r;
long long pr,add,mul;
}t[4*ma+2];
void bulid(int p,int l,int r){
t[p].l=l;t[p].r=r;
t[p].mul = 1;
t[p].add = 0;
if(l==r){
t[p].pr=a[l]%h;
return;
}
int mid=l+r>>1;
bulid(p*2,l,mid);
bulid(p*2+1,mid+1,r);
t[p].pr=(t[p*2].pr+t[p*2+1].pr)%h;
}
void sp(int p){
if (t[p].mul == 1 && t[p].add == 0) return;
else{
t[p*2].pr=(t[p*2].pr*t[p].mul+t[p].add*(t[p*2].r-t[p*2].l+1))%h;
t[p*2+1].pr=(t[p*2+1].pr*t[p].mul+t[p].add*(t[p*2+1].r-t[p*2+1].l+1))%h;
t[p*2].add=(t[p*2].add*t[p].mul+t[p].add)%h;
t[p*2+1].add=(t[p*2+1].add*t[p].mul+t[p].add)%h;
t[p*2].mul=(t[p*2].mul*t[p].mul)%h;
t[p*2+1].mul=(t[p*2+1].mul*t[p].mul)%h;
t[p].add=0;t[p].mul=1;
}
}
void change1(int p,int x,int y,long long z){
if(x<=t[p].l && y>=t[p].r){
t[p].pr = (t[p].pr * z) % h;
t[p].mul = (t[p].mul * z) % h;
t[p].add = (t[p].add * z) % h;
return;
}
sp(p);
int mid=t[p].l+t[p].r>>1;
if(x<=mid) change1(p*2,x,y,z);
if(y>mid) change1(p*2+1,x,y,z);
t[p].pr=(t[p*2].pr+t[p*2+1].pr)%h;
}
void change2(int p,int x,int y,long long z){
if(x<=t[p].l && y>=t[p].r){
t[p].pr = (t[p].pr + z * (t[p].r - t[p].l + 1)) % h;
t[p].add = (t[p].add + z) % h;
return;
}
sp(p);
int mid=t[p].l+t[p].r>>1;
if(x<=mid) change2(p*2,x,y,z);
if(y>mid) change2(p*2+1,x,y,z);
t[p].pr = (t[p*2].pr + t[p*2+1].pr) % h;;
}
long long ask(int p, int x, int y) {
if (x <= t[p].l && y >= t[p].r) return t[p].pr % h;
sp(p);
int mid = t[p].l + t[p].r >> 1;
long long ans = 0;
if (x <= mid) ans = (ans + ask(p*2, x, y)) % h;
if (y > mid) ans = (ans + ask(p*2+1, x, y)) % h;
return ans % h;
}
int main(){
ios_base::sync_with_stdio(false);
cin.tie(nullptr);
int n,m;
cin>>n>>m>>h;
for(int i=1;i<=n;i++){
cin>>a[i];
a[i]%=h;
}
bulid(1,1,n);
for(int i=1;i<=m;i++)
{
int q,x,y;
long long z;
cin>>q;
if(q==1){
cin>>x>>y>>z;
z=z%h;
change1(1,x,y,z);
}
else if(q==2){
cin>>x>>y>>z;
z=z%h;
change2(1,x,y,z);
}
else {
cin>>x>>y;
cout<<ask(1,x,y)<<endl;
}
}
return 0;
}