ZKW线段树
数组定义
const ll M=1<<19;//从1开始,不能修改0和M
ll T[M+M];
单点修改区间查询
void modify(int n,int v){
for(T[n+=M]=v,n>>=1;n;n>>=1)
T[n]=T[n+n]+T[n+n+1];
}
ll query(ll l,ll r){
ll ans=0;
for(l+=M-1,r+=M+1;l^r^1;l>>=1,r>>=1){
if(~l&1) ans+=T[l^1];
if(r&1) ans+=T[r^1];
}
return ans;
}
单点修改区间最值
void modify(ll n,ll v){
for(T[n+=M]=v,n>>=1;n;n>>=1)
T[n]=max(T[n+n],T[n+n+1]);
}
ll query(ll l,ll r){
ll rmax=-INF,lmax=-INF;
for(l+=M-1,r+=M+1;l^r^1;l>>=1,r>>=1){
if(~l&1) lmax=max(lmax,T[l^1]);
if(r&1) rmax=max(rmax,T[r^1]);
}
return max(lmax,rmax);
}
区间修改单点查询
void add(int l,int r,int w){
for(l+=m-1,r+=m+1;l^r^1;l>>=1,r>>=1){
if(~l&1) T[l^1]+=w;
if(r&1) T[r^1]+=w;
}
}
int query(int x){
int ans=0;
for(x+=m;x;x>>=1)
ans+=T[x];
return ans;
}
传统线段树
权值线段树(单点修改,区间查询,全局第K小)
#define lson rt<<1
#define rson rt<<1|1
using namespace std;
int T[maxn<<2],n;
inline void push_now(int k){
T[k]=T[k<<1]+T[k<<1|1];
}
void add(int rt,int l,int r,int p,int val){//[l,r]
if(l==r){
T[rt]+=val;
return;
}
int mid=(l+r)>>1;
if(p<=mid) add(lson,l,mid,p,val);
if(p>mid) add(rson,mid+1,r,p,val);
push_now(rt);
}
int ask(int rt,int l,int r,int k){//全局第k小
if(T[rt]<k) return -1;
if(l==r) return l;
int mid=(l+r)>>1;
if(T[lson]>=k)
return query(lson,l,mid,k);
else
return query(rson,mid+1,r,k-T[lson]);
}
int query(int rt,int l,int r,int ql,int qr){//区间和
int res=0;
if(ql<=l&&r<=qr)
return T[rt];
int mid=(l+r)>>1;
if(ql<=mid) res+=ask(lson,l,mid,ql,qr);
if(qr>mid) res+=ask(rson,mid+1,r,ql,qr);
return res;
}
区间覆盖区间和
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
typedef long long ll;
const ll maxn=1e5+5;
const ll INF=1e17;
ll a[maxn],ans[maxn<<2],lazy[maxn<<2];
ll n,m,t;
inline void update(ll k){
ans[k]=ans[k<<1]+ans[k<<1|1];
}
inline void push_down(ll x,ll l,ll r){
if(lazy[x]==-1)return;
ll mid=(l+r)>>1;
lazy[x<<1]=lazy[x<<1|1]=lazy[x];
ans[x<<1]=lazy[x]*(mid-l+1);
ans[x<<1|1]=lazy[x]*(r-mid);
lazy[x]=-1;
}
void build(ll rt,ll l,ll r){
lazy[rt]=-1;
if(l==r){
ans[rt]=a[l];return;
}
ll mid=(l+r)>>1;
build(rt<<1,l,mid);
build(rt<<1|1,mid+1,r);
update(rt);
}
void modify(ll rt,ll l,ll r,ll ql,ll qr, ll w){
if(ql<=l&&r<=qr){
ans[rt]=w*(r-l+1);
lazy[rt]=w;
return;
}
push_down(rt,l,r);
ll mid=(r+l)>>1;
if(ql<=mid) modify(rt<<1,l,mid,ql,qr,w);
if(qr>mid) modify(rt<<1|1,mid+1,r,ql,qr,w);
update(rt);
}
ll query(ll rt,ll l,ll r,ll ql,ll qr){
ll res=0;
if(ql<=l && r<=qr)
return ans[rt];
push_down(rt,l,r);
ll mid=(r+l)>>1;
if(ql<=mid) res+=query(rt<<1,l,mid,ql,qr);
if(qr>mid) res+=query(rt<<1|1,mid+1,r,ql,qr);
return res;
}
int main(){
cin>>n>>m;
memset(lazy,-1,sizeof(lazy));
build(1,1,n);
ll b,c,d,e;
for(ll i=1;i<=m;i++){
scanf("%lld",&b);
if(b==1){
scanf("%lld%lld%lld",&c,&d,&e);
modify(1,1,n,c,d,e);
}
if(b==2){
scanf("%lld%lld",&d,&e);
cout<<query(1,1,n,d,e)<<endl;
}
}
}
区间加,区间和
#include <bits/stdc++.h>
#define lson (rt<<1)
#define rson (rt<<1|1)
#define mid ((l+r)>>1)
typedef long long ll;
using namespace std;
const int maxn=1e5+5;
ll T[maxn<<2],lazy[maxn<<2];
ll a[maxn];
void push_up(int rt){
T[rt]=T[lson]+T[rson];
}
void push_down(int rt,int l,int r){
if(!lazy[rt])return;
T[lson]+=(mid-l+1)*lazy[rt];
T[rson]+=(r-mid-1+1)*lazy[rt];
lazy[lson]+=lazy[rt];
lazy[rson]+=lazy[rt];
lazy[rt]=0;
}
void build(int rt,int l,int r){
lazy[rt]=0;
if(l==r){
T[rt]=a[l];
return;
}
build(lson,l,mid);
build(rson,mid+1,r);
push_up(rt);
}
void add(int rt,int l,int r,int ql,int qr,ll value){
if(l>=ql && r<=qr){
T[rt]+=(r-l+1)*value;
lazy[rt]+=value;
return;
}
push_down(rt,l,r);
if(ql<=mid)add(lson,l,mid,ql,qr,value);
if(qr>=mid+1)add(rson,mid+1,r,ql,qr,value);
push_up(rt);
}
ll query(int rt,int l,int r,int ql,int qr){
if(l>=ql && r<=qr){
return T[rt];
}
push_down(rt,l,r);
ll ans=0;
if(ql<=mid)ans+=query(lson,l,mid,ql,qr);
if(qr>=mid+1)ans+=query(rson,mid+1,r,ql,qr);
return ans;
}
int main () {
int n,m;
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++){
scanf("%lld",&a[i]);
}
build(1,1,n);
while(m--){
int opt,x,y;
ll k;
scanf("%d",&opt);
if(opt==1){
scanf("%d%d%lld",&x,&y,&k);
add(1,1,n,x,y,k);
}
else{
scanf("%d%d",&x,&y);
ll ans=query(1,1,n,x,y);
printf("%lld\n",ans);
}
}
}
区间加/乘 区间和
const int maxn=1e5+5;
ll mod;
ll a[maxn],ans[maxn<<2],lzm[maxn<<2],lza[maxn<<2];
ll n,m;
inline void push_up(ll k){
ans[k]=(ans[k<<1]+ans[k<<1|1])%mod;
}
inline void work_add(ll x,ll l,ll r,ll add){
lza[x]=(lza[x]+add)%mod;
ans[x]=(ans[x]+add*(r-l+1) ) %mod;
}
inline void work_mul(ll x,ll l,ll r,ll mul){
lza[x]=(lza[x]*mul%mod);
lzm[x]=(lzm[x]*mul%mod);
ans[x]=ans[x]*mul%mod;
}
inline void push_down(ll x,ll l,ll r){
ll mid=(l+r)>>1;
if(lzm[x]!=1){
work_mul(x<<1,l,mid,lzm[x]);
work_mul(x<<1|1,mid+1,r,lzm[x]);
}
if(lza[x]!=0){
work_add(x<<1,l,mid,lza[x]);
work_add(x<<1|1,mid+1,r,lza[x]);
}
lzm[x]=1;lza[x]=0;
}
void build(ll rt,ll l,ll r){
lza[rt]=0;lzm[rt]=1;
if(l==r){
ans[rt]=a[l];
return;
}
ll mid=(l+r)>>1;
build(rt<<1,l,mid);
build(rt<<1|1,mid+1,r);
push_up(rt);
}
void mul(ll rt,ll l,ll r,ll ql,ll qr, ll w){
if(ql<=l&&r<=qr){
work_mul(rt,l,r,w);
return;
}
push_down(rt,l,r);
ll mid=(r+l)>>1;
if(ql<=mid) mul(rt<<1,l,mid,ql,qr,w);
if(qr>mid) mul(rt<<1|1,mid+1,r,ql,qr,w);
push_up(rt);
}
void add(ll rt,ll l,ll r,ll ql,ll qr, ll w){
if(ql<=l && r<=qr){
work_add(rt,l,r,w);
return;
}
push_down(rt,l,r);
ll mid=(r+l)>>1;
if(ql<=mid) add(rt<<1,l,mid,ql,qr,w);
if(qr>mid) add(rt<<1|1,mid+1,r,ql,qr,w);
push_up(rt);
}
ll query(ll rt,ll l,ll r,ll ql,ll qr){
ll res=0;
if(ql<=l && r<=qr)
return ans[rt];
push_down(rt,l,r);
ll mid=(r+l)>>1;
if(ql<=mid) res=(res+query(rt<<1,l,mid,ql,qr))%mod;
if(qr>mid) res=(res+query(rt<<1|1,mid+1,r,ql,qr))%mod;
return res;
}
例题
P5490扫描线
注意:扫描线中的线段树叶子节点是r-l=1的,因为一个点是没有贡献的。并且两个相邻区间的左边的右端点和右边的左端点是一样的,这样才能表示出所有线段。
#include <bits/stdc++.h>
#define lson rt<<1
#define rson rt<<1|1
#define mid ((l+r)>>1)
using namespace std;
typedef long long ll;
const int maxn=2e5+5;
struct Xian{
int y,x1,x2;
int io;
}xian[maxn];
bool cmp(Xian a,Xian b){
return a.y<b.y;
}
int lisan[maxn];
int len[maxn<<2];
int cover[maxn<<2];
void push_up(int rt,int l,int r){
if(cover[rt])len[rt]=lisan[r]-lisan[l];
else if(r==l+1)len[rt]=0;//叶子节点
else len[rt]=len[rson]+len[lson];
}
void update(int rt,int l,int r,int ql,int qr,int value){
if(l>qr || r<ql)return;
if(ql<=l && r<=qr){
cover[rt]+=value;
push_up(rt,l,r);
return;
}
if(r==l+1)return;//到叶子节点
if(ql<=mid-1)update(lson,l,mid,ql,qr,value);
if(qr>=mid+1)update(rson,mid,r,ql,qr,value);
push_up(rt,l,r);
}
int main () {
int n;
scanf("%d",&n);
int xiancnt=0,lisancnt=0;
for(int i=1;i<=n;i++){
int x1,y1,x2,y2;
scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
xian[++xiancnt]={y1,x1,x2,1};
xian[++xiancnt]={y2,x1,x2,-1};
lisan[++lisancnt]=x1;
lisan[++lisancnt]=x2;
}
sort(xian+1,xian+1+xiancnt,cmp);
sort(lisan+1,lisan+1+lisancnt);
int lisansize=unique(lisan+1,lisan+1+lisancnt)-(lisan+1);
ll ans=0;
for(int i=1;i<=xiancnt;i++){
if(i>1)
ans+=(ll)(xian[i].y-xian[i-1].y)*(len[1]);
int l=lower_bound(lisan+1,lisan+1+lisansize,xian[i].x1)-lisan;
int r=lower_bound(lisan+1,lisan+1+lisansize,xian[i].x2)-lisan;
int io=xian[i].io;
update(1,1,lisansize,l,r,io);
}
printf("%lld\n",ans);
}