loj 6279分塊入門

題目鏈接

https://loj.ac/problem/6279

題意

給出一個長爲 nn的數列,以及nn個操作,操作涉及區間加法,詢問區間內小於某個值xx的前驅(比其小的最大元素)。

思路

分塊區間修改板題。
分塊的時候,就對每一個塊進行排序,查找時,邊塊角塊依舊暴力,整塊使用 lower_boundlower\_boundupper_boundupper\_bound 二分查找。
注意,邊塊角塊修改後所在塊要重新排序。

參考代碼

#include <bits/stdc++.h>
using namespace std;
const int inf = 0x3f3f3f3f;
int n,block,cnt;
int a[100010],addv[400],belong[100010];
vector<int> vc[400];
void Sort() {
	for(int i=1; i<=cnt; i++) {
		sort(vc[i].begin(),vc[i].end());
	}
}
void update(int blockn) {
	vc[blockn].clear();
	for(int i=(blockn-1)*block+1; i<=blockn*block; i++) {
		vc[blockn].push_back(a[i]);
	}
	sort(vc[blockn].begin(),vc[blockn].end());
}
void modify(int l,int r,int add) {
	for(int i=l; i<=min(belong[l]*block,r); i++) {
		a[i]+=add;
	}
	update(belong[l]);
	if(belong[l]!=belong[r]) {
		for(int i=(belong[r]-1)*block+1; i<=r; i++) {
			a[i]+=add;
		}
		update(belong[r]);
	}
	for(int i=belong[l]+1; i<belong[r]; i++) {
		addv[i]+=add;
	}
}
int query(int l,int r,int maxn) {
	int ans=-inf;
	for(int i=l; i<=min(belong[l]*block,r); i++) {
		if(a[i]+addv[belong[i]]<maxn) {
			ans=max(ans,a[i]+addv[belong[i]]);
		}
	}
	if(belong[l]!=belong[r]) {
		for(int i=(belong[r]-1)*block+1; i<=r; i++) {
			if(a[i]+addv[belong[i]]<maxn) {
				ans=max(ans,a[i]+addv[belong[i]]);
			}
		}
	}
	for(int i=belong[l]+1; i<belong[r]; i++) {
		if(vc[i].at(0)+addv[i]>=maxn) {
			continue;
		}
		int k=lower_bound(vc[i].begin(),vc[i].end(),maxn-addv[i])-vc[i].begin();
		ans=max(ans,vc[i].at(k-1)+addv[i]);
	}
	return ans;
}
int main() {
	int n;
	scanf("%d",&n);
	block=sqrt(n);
	for(int i=1; i<=n; i++) {
		scanf("%d",&a[i]);
		belong[i]=(i-1)/block+1;
		vc[belong[i]].push_back(a[i]);
		if(i%block==1) {
			cnt++;
		}
	}
	Sort();
	for(int i=1; i<=n; i++) {
		int op,l,r,c;
		scanf("%d%d%d%d",&op,&l,&r,&c);
		if(op==0) {
			modify(l,r,c);
		} else {
			int k=query(l,r,c);
			if(k==-inf) {
				printf("-1\n");
				continue;
			}
			printf("%d\n",k);
		}
	}
	return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章