题解——loj6279 数列分块入门3 (分块)

用set维护有序序列

或许sort也可以,但这题的前驱定义是严格小于

所以要去重

然后就是记得自己打的加法tag在query的时候一定要算上

话说这题数据有点fake啊忘了查询算上自己的标记了还有70

然后还有玄学优化

块的大小从( sqrt x )变成1000每个点能快300ms的样子qwq

似乎原理是减少维护的set的个数吧

#include <cstdio>
#include <algorithm>
#include <cstring>
#include <set>
#include <cmath>
using namespace std;
const int MAXN = 101000;
int n,sz,num,tag[MAXN],a[MAXN],belong[MAXN];
set<int> b[105];
void calbe(int n){
	for(int i=1;i<=n;i++)
		belong[i]=(i-1)/sz+1;
}
void reset(int x){
	b[x].clear();
	for(int i=(x-1)*sz+1;i<=min(x*sz,n);i++)
		b[x].insert(a[i]);
}
void update(int l,int r,int w){
	int xl=belong[l];
	int xr=belong[r];
	for(int i=l;i<=min(xl*sz,r);i++){
		b[xl].erase(a[i]);
		a[i]+=w;
		b[xl].insert(a[i]);
		}
	if(xl!=xr){
		for(int i=(xr-1)*sz+1;i<=r;i++){
			b[xr].erase(a[i]);
			a[i]+=w;
			b[xr].insert(a[i]);
		}
	}
	for(int i=xl+1;i<=xr-1;i++)
		tag[i]+=w;
}
int query(int l,int r,int w){
	int xl=belong[l];
	int xr=belong[r];
	int ans=-1;
	for(int i=l;i<=min(r,xl*sz);i++)
		if(a[i]<w-tag[xl]&&a[i]+tag[xl]>ans)
			ans=a[i]+tag[xl];
	if(xl!=xr){
		for(int i=(xr-1)*sz+1;i<=r;i++)
			 if(a[i]<w-tag[xr]&&a[i]+tag[xr]>ans)
			 	ans=a[i]+tag[xr];
	}
	for(int i=xl+1;i<=xr-1;i++){
		set<int> :: iterator it=b[i].lower_bound(w-tag[i]);
		if(it==b[i].begin())
			continue;
		it--;
		if(ans<(*it+tag[i]))
			ans=*it+tag[i];
	}
	return ans;
}
int main(){
	scanf("%d",&n);
	sz=1000;
	calbe(n);
	num=n/sz;
	if(n%sz)
		num++;
	for(int i=1;i<=n;i++)
		scanf("%d",&a[i]);
	for(int i=1;i<=num;i++){
		reset(i);
	} 
	for(int i=1;i<=n;i++){
		int opt,l,r,c;
		scanf("%d %d %d %d",&opt,&l,&r,&c);
		if(opt==0)
			update(l,r,c);
		else
			printf("%d
",query(l,r,c));
	}
	return 0;
}
原文地址:https://www.cnblogs.com/dreagonm/p/9507419.html