zoukankan      html  css  js  c++  java
  • 线段树模板

    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);
    }
    
  • 相关阅读:
    【shell】日志切割
    【PHP】SVN版本差异导出
    Linux服务器上安装JDK
    Linux 下node环境安装
    CentOS 7.3安装mariadb
    Centos 7.4 自动初始化docker环境,配置docker镜像仓库
    Shell 模板 (Yes or NO)
    Linux修改时间和时区
    lvm方式挂载盘及扩容
    安装ansible
  • 原文地址:https://www.cnblogs.com/ucprer/p/11275901.html
Copyright © 2011-2022 走看看