线段树模板

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);
}
posted @ 2019-07-31 14:05  UCPRER  阅读(210)  评论(0编辑  收藏  举报