动态开点线段树(线段树1.5)

适用于操作数小,但数组长度大的。

#include<bits/stdc++.h>
using namespace std;
typedef unsigned long long ll;
const ll maxn=5e6+5;
ll n,m,cnt,rt;
struct node{
    ll ls,rs,sum,tag;
}d[maxn];
void pushup(ll p){
    d[p].sum=(d[p].ls?d[d[p].ls].sum:0)+(d[p].rs?d[d[p].rs].sum:0);
}
void pushdown(ll p,ll l,ll r){
	ll mid=(l+r)/2;
	if(d[p].tag){
		if(!d[p].ls){
			d[p].ls=++cnt;
		}
		if(!d[p].rs){
			d[p].rs=++cnt;
		}
		d[d[p].ls].sum+=d[p].tag*(mid-l+1);
	    d[d[p].rs].sum+=d[p].tag*(r-mid);
	    d[d[p].ls].tag+=d[p].tag;
	    d[d[p].rs].tag+=d[p].tag;
	    d[p].tag=0;
	}
}
void add(ll &p,ll l,ll r,ll x,ll y,ll k){
	if(!p){
		p=++cnt;
	}
    if(l>=x&&r<=y){
        d[p].sum+=k*(r-l+1);
        d[p].tag+=k;
        return;
    }
    pushdown(p,l,r);
    ll mid=(l+r)/2;
    if(mid>=x){
        add(d[p].ls,l,mid,x,y,k);
    }
    if(mid<y){
        add(d[p].rs,mid+1,r,x,y,k);
    }
    pushup(p);
}
ll query(ll p,ll l,ll r,ll x,ll y){
	if(!p){
		return 0;
	}
    if(l>=x&&r<=y){
        return d[p].sum;
    }
    pushdown(p,l,r);
    ll mid=(l+r)/2,ans=0;
    if(mid>=x){
        ans+=query(d[p].ls,l,mid,x,y);
    }
    if(mid<y){
        ans+=query(d[p].rs,mid+1,r,x,y);
    }
    return ans;
}
int main(){
	ios::sync_with_stdio(false);
	cin.tie(nullptr);
    cin>>n>>m;
    for(ll i=1;i<=m;i++){
        ll opt,x,y,k;
        cin>>opt>>x>>y;
        if(opt==1){
            cin>>k;
            add(rt,1,n,x,y,k);
        }else{
        	ll ans1=query(rt,1,n,x,y);
        	ll ans2=(x+y)*(y-x+1)/2;
            cout<<ans1+ans2<<"\n";
        }
    }
    return 0;
}
posted @ 2026-10-17 16:26  beiciqi  阅读(2)  评论(0)    收藏  举报