數列分塊2(學習)

數列分塊2(學習)

傳送門

用途:區間加法,區間查找小於cc的數的個數。

思路:對於區間加法依舊分塊處理,由於是查找小於cc的數的個數,顯然要用到排序,所以我們先分塊,然後對每一塊進行排序。因爲區間加法存在對非整塊的處理,所以區間加後數的大小位置可能發生變化,所以要進行重新排序。對於區間查找也是分塊思想,用二分查找實現即可。

時間複雜度:O(nlogn+nnlogn)O(nlogn+n\sqrt{n}log\sqrt{n})

AC代碼:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e5+5;
#define mst(a) memset(a,0,sizeof a)
int n,bk,a[N],tag[N],bl[N]; 
vector<int>v[N];
void reset(int x){ //重新對塊排序. 
	v[x].clear();
		for(int i=(x-1)*bk+1;i<=min(x*bk,n);i++)
			v[x].push_back(a[i]);
		sort(v[x].begin(),v[x].end());
}
void add(int l,int r,int c){
	for(int i=l;i<=min(bk*bl[l],r);i++) //左邊不完整的塊 
		a[i]+=c; 
	reset(bl[l]);//每次要重置。 
	if(bl[l]!=bl[r]){
		for(int i=(bl[r]-1)*bk+1;i<=r;i++) //右邊不完整的塊 
			a[i]+=c;
		reset(bl[r]);//重置. 
	}
	for(int i=bl[l]+1;i<=bl[r]-1;i++)  
		 tag[i]+=c;
}
int query(int l,int r,int c){
	int ans=0;
	for(int i=l;i<=min(bk*bl[l],r);i++)  //查詢也是分整塊與非整塊處理. 
			if(a[i]+tag[bl[l]]<c) ans++;
	if(bl[l]!=bl[r]){
		for(int i=(bl[r]-1)*bk+1;i<=r;i++)
			if(a[i]+tag[bl[r]]<c) ans++;
	}
	for(int i=bl[l]+1;i<=bl[r]-1;i++){
		 int x=c-tag[i];
		 ans+=lower_bound(v[i].begin(),v[i].end(),x)-v[i].begin();
	}
	return ans;
}
int main(){
	scanf("%d",&n),bk=sqrt(n);
	for(int i=1;i<=n;i++) scanf("%d",&a[i]);
	for(int i=1;i<=n;i++){
		bl[i]=(i-1)/bk+1;
		v[bl[i]].push_back(a[i]);
	}
	for(int i=1;i<=bl[n];i++)
		sort(v[i].begin(),v[i].end());
	for(int i=1,op,l,r,c;i<=n;i++){
		  scanf("%d%d%d%d",&op,&l,&r,&c);
		  if(!op) add(l,r,c);
		  else printf("%d\n",query(l,r,c*c));
	} 
	return 0;
} 
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章