#线段树,Beats#CF855F Nagini

题目传送门


分析

先不考虑正负数都要存在,那么相当于正值维护区间最小值,负值维护区间最大值(取反复用)。

将各自区间和加起来,问题是权值和只有正负值同时存在的时候才计算。

由于一方答案不超过 \(10^5\times 10^9<2^{50}\),因此将区间和变成区间和对 \(2^{50}\) 取模。

额外维护两棵线段树操作相同,只是正值维护时将负值的对应区间对 \(0\) 取最小值,反之亦然。

这样如果是 inf 的话另一方正负值的线段树的答案相减就会被抵消掉,而我方取模还是消掉了。

用四棵线段树维护区间最值 Beats 就可以了。


代码

#include <iostream>
#include <algorithm>
using namespace std;
const int N=100011;
typedef long long lll;
const lll inf=(1ll<<50)-1;
struct Segment_Tree{
	lll mx[N<<2],semx[N<<2],w[N<<2];
	int cntmx[N<<2];
	void pup(int k){
		w[k]=(w[k<<1]+w[k<<1|1])&inf;
		if (mx[k<<1]==mx[k<<1|1])
			mx[k]=mx[k<<1],semx[k]=max(semx[k<<1],semx[k<<1|1]),cntmx[k]=cntmx[k<<1]+cntmx[k<<1|1];
		else if (mx[k<<1]>mx[k<<1|1])
			mx[k]=mx[k<<1],semx[k]=max(semx[k<<1],mx[k<<1|1]),cntmx[k]=cntmx[k<<1];
		else mx[k]=mx[k<<1|1],semx[k]=max(mx[k<<1],semx[k<<1|1]),cntmx[k]=cntmx[k<<1|1];
	}
	void ptag_max(int k,lll z){
		if (z>=mx[k]) return;
		lll t=(z&inf)-(mx[k]&inf);
		w[k]=(w[k]+t*cntmx[k]+inf+1)&inf;
		mx[k]=z;
	}
	void pdown(int k){
		if (mx[k<<1]>mx[k]) ptag_max(k<<1,mx[k]);
		if (mx[k<<1|1]>mx[k]) ptag_max(k<<1|1,mx[k]);
	}
	void build(int k,int l,int r){
		if (l==r){
			w[k]=0,mx[k]=inf+1,semx[k]=-inf-1,cntmx[k]=1;
			return;
		}
		int mid=(l+r)>>1;
		build(k<<1,l,mid);
		build(k<<1|1,mid+1,r);
		pup(k);
	}
	void update(int k,int l,int r,int x,int y,lll z){
		if (z>=mx[k]) return;
		if (l==x&&r==y&&z>semx[k]){
			ptag_max(k,z);
			return;
		}
		int mid=(l+r)>>1;
		pdown(k);
		if (y<=mid) update(k<<1,l,mid,x,y,z);
		    else if (x>mid) update(k<<1|1,mid+1,r,x,y,z);
		        else update(k<<1,l,mid,x,mid,z),update(k<<1|1,mid+1,r,mid+1,y,z);
		pup(k);
	}
	lll query(int k,int l,int r,int x,int y){
		if (l==x&&r==y) return w[k];
		int mid=(l+r)>>1;
		pdown(k);
		if (y<=mid) return query(k<<1,l,mid,x,y);
		    else if (x>mid) return query(k<<1|1,mid+1,r,x,y);
		        else return (query(k<<1,l,mid,x,mid)+query(k<<1|1,mid+1,r,mid+1,y))&inf;
	}
}Tre[4];
int main(){
	ios::sync_with_stdio(0);
	cin.tie(0),cout.tie(0);
	int q,n=100000; cin>>q;
	for (int i=0;i<4;++i) Tre[i].build(1,1,n);
	for (;q;--q){
		int opt,l,r; cin>>opt>>l>>r; --r;
		if (opt==1){
			lll k; cin>>k;
			if (k>0){
				Tre[0].update(1,1,n,l,r,k);
				Tre[1].update(1,1,n,l,r,k);
				Tre[3].update(1,1,n,l,r,0);
			}
			else{
				k=-k;
				Tre[2].update(1,1,n,l,r,k);
				Tre[3].update(1,1,n,l,r,k);
				Tre[1].update(1,1,n,l,r,0);
			}
		}
		else{
			lll ans=Tre[0].query(1,1,n,l,r)+Tre[2].query(1,1,n,l,r)-Tre[1].query(1,1,n,l,r)-Tre[3].query(1,1,n,l,r);
			cout<<((ans+2*(inf+1))&inf)<<'\n';
		}
	}
	return 0;
}
posted @ 2026-09-29 09:34  lemondinosaur  阅读(7)  评论(0)    收藏  举报