二逼平衡树-分块

版权声明:转载注明出处,谢谢,有问题可以向博主联系 https://blog.csdn.net/VictoryCzt/article/details/84798051

题目地址【IN-luogubzoj,loj也有,但是题目可能有点不同,这里的代码是luogu上的AC代码

本来想练练树套树,结果一看数据范围,就试着写了个大力分块,结果过了-_-||,后面再练树套树吧。


对于这几个操作,用分块的话,暴力非常好写:

我们先将原数列分块,对于新的分了块的数列每个快内排个序,复杂度 O ( n l o g n ) O(nlogn)

  • 查询k在区间内的排名

边角暴力统计,块内二分即可。

  • 查询区间内排名为k的值

二分值,然后去统计这个值的排名即可

  • 修改某一位值上的数值

在原数组上把它改了,然后将它所在的块还原重新排个序。

  • 查询k在区间内的前驱(前驱定义为严格小于x,且最大的数,若不存在输出-2147483647)

边角暴力,块内二分

  • 查询k在区间内的后继(后继定义为严格大于x,且最小的数,若不存在输出2147483647)

同理

注意:这里边角暴力时,必须在原数组上查找,不能在排好序的上面找,否则会出错。

复杂度为 n n l o g n n\sqrt{n}log\sqrt{n} 卡的过去。

扫描二维码关注公众号,回复: 4566687 查看本文章

丑陋代码新鲜出炉:

这里我分的300大小的块。

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int inf=0x7fffffff;
const int N=245,M=1e5+1,L=1e5+10;
int n,m,val[L],bef[L],up;
int stpos[N],enpos[N],bel[L],tot;
int calc_1(int l,int r,int v){
	int st=l,en=r;
	if(val[l]>v)return 0;
	int mid,ans=r+5;
	while(l<=r){
		mid=l+r>>1;
		if(val[mid]<v)l=mid+1,ans=mid;
		else r=mid-1;
	}
	if(ans>en||ans<st)return 0;
	return ans-st+1;
}
int find_rank(int l,int r,int k){
	int ans=0;
	if(bel[l]==bel[r]){
		for(int i=l;i<=r;i++){
			if(bef[i]<k)++ans;
		}
		return ans+1;
	}
	for(int i=l;i<=enpos[bel[l]];i++){if(bef[i]<k)++ans;}
	for(int i=stpos[bel[r]];i<=r;i++){if(bef[i]<k)++ans;}
	for(int i=bel[l]+1;i<bel[r];i++){ans+=calc_1(stpos[i],enpos[i],k);}	
	return ans+1;
}
int solve_1(){
	int l,r,k;
	scanf("%d%d%d",&l,&r,&k);
	return find_rank(l,r,k);
}
int solve_2(){
	int L=0,R=1e8,ans=R,mid,k,l,r,now;
	scanf("%d%d%d",&l,&r,&k);
	while(L<=R){
		mid=L+R>>1;
		now=find_rank(l,r,mid);
		if(now>k)R=mid-1;
		else L=mid+1,ans=mid;
	}
	return ans;
}
void solve_3(){
	int p,k;
	scanf("%d%d",&p,&k);
	bef[p]=k;
	for(int i=stpos[bel[p]];i<=enpos[bel[p]];i++)val[i]=bef[i];
	sort(val+stpos[bel[p]],val+enpos[bel[p]]+1);
}
int find_mid_4(int l,int r,int v){
	int mid,ans=-inf;
	while(l<=r){
		mid=l+r>>1;
		if(val[mid]<v){
			if(val[mid]>ans)ans=val[mid];
			l=mid+1;
		}else r=mid-1;
	}
	if(val[l]<v&&val[l]>ans)ans=val[l];
	return ans;
}
int find_mid_5(int l,int r,int v){
	int mid,ans=inf;
	while(l<=r){
		mid=l+r>>1;
		if(val[mid]>v){
			if(val[mid]<ans)ans=val[mid];
			r=mid-1;
		}else l=mid+1;
	}
	if(val[l]>v&&val[l]<ans)ans=val[l];
	return ans;
}
int solve_4(){
	int l,r,k,ans=-inf;
	scanf("%d%d%d",&l,&r,&k);
	if(bel[l]==bel[r]){
		for(int i=l;i<=r;i++){
			if(bef[i]<k){
				if(bef[i]>ans)ans=bef[i];
			}			
		}
		return ans;
	}	
	for(int i=l;i<=enpos[bel[l]];i++){
		if(bef[i]<k){
			if(bef[i]>ans)ans=bef[i];
		}
	}
	for(int i=stpos[bel[r]];i<=r;i++){
		if(bef[i]<k){
			if(bef[i]>ans)ans=bef[i];
		}
	}
	for(int i=bel[l]+1;i<bel[r];i++){
		int now=find_mid_4(stpos[i],enpos[i],k);
		if(now<k){
			if(now>ans)ans=now;
		}
	}
	return ans;
}
int solve_5(){
	int l,r,k,ans=inf;
	scanf("%d%d%d",&l,&r,&k);
	if(bel[l]==bel[r]){
		for(int i=l;i<=r;i++){
			if(bef[i]>k){
				if(bef[i]<ans)ans=bef[i];
			}			
		}
		return ans;
	}
	for(int i=l;i<=enpos[bel[l]];i++){
		if(bef[i]>k){
			if(bef[i]<ans)ans=bef[i];
		}
	}
	for(int i=stpos[bel[r]];i<=r;i++){
		if(bef[i]>k){
			if(bef[i]<ans)ans=bef[i];
		}
	}
	for(int i=bel[l]+1;i<bel[r];i++){
		int now=find_mid_5(stpos[i],enpos[i],k);
		if(now>k){
			if(now<ans)ans=now;
		}
	}
	return ans;	
}
int opt;
int main(){
	scanf("%d%d",&n,&m);
	int fj=0;up=n+m;
	for(int i=1;i<=n;i++){
		scanf("%d",&val[i]);bef[i]=val[i];
		if(!fj){
			fj=300;
			enpos[tot]=i-1;
			stpos[++tot]=i;
		}
		--fj;bel[i]=tot;
	}	enpos[tot]=n;
	for(int i=1;i<=tot;i++){sort(val+stpos[i],val+enpos[i]+1);}
	while(m--){
		scanf("%d",&opt);
		switch(opt){
			case 1:{
				printf("%d\n",solve_1());
				break;
			}
			case 2:{
				printf("%d\n",solve_2());
				break;
			}
			case 3:{
				solve_3();
				break;
			}
			case 4:{
				printf("%d\n",solve_4());
				break;
			}
			case 5:{
				printf("%d\n",solve_5());
				break;
			}
		}
	}
	return 0;
} 

猜你喜欢

转载自blog.csdn.net/VictoryCzt/article/details/84798051