2020 CCPC Wannafly Winter Camp Day1 7-9 1I. K小数查询 (分块写法)

块内打个lazy标记,表示块内元素都要与lz取min,每次更新操作,整块lazy标记处理

两端剩下的非整块暴力处理。

查询时二分转化为查询区间内小于k的个数。

然后整块部分先判断lazy标记是否小于k,小于说明区间所有元素都小于k

否则二分处理,二分找到第一个大于k的元素,然后之前的元素一定小于等于k,由于lazy大于k,对前面元素没有影响

对于非整块部分,暴力更新后处理。

更新复杂度 O 根号n 

查询复杂度 O 根号n *logn* log(根号n)

#include<bits/stdc++.h>
using namespace std;
#define pb push_back
const int M =8e4+7;
int size,bnm;//每块的大小,块的个数
int L[M],R[M]; //每块的左边界和右边界
int lz[M];//每块的lz标记  即这一块的所有数都执行与lz[i]取min操作
vector<int>v[M];// 每块用vector储存 
int a[M];
void up(int l,int r,int x)
{
	int id=(l-1)/size+1;//属于第几块 
	//cout<<id<<"  "<<endl;
	if(L[id]!=l)
	{
		v[id].clear();
		for(int i=L[id];i<=R[id];i++)
		{
			a[i]=min(a[i],lz[id]);
			if(l<=i&&i<=r)a[i]=min(a[i],x);
			v[id].pb(a[i]);
		}
		sort(v[id].begin(),v[id].end());
		id++;
	}
	while(id<=bnm&&R[id]<=r)//把整块的块更新 
	{
		lz[id]=min(lz[id],x);
		id++;
	}
	if(id>bnm||L[id]>r)return ;
	//还剩下一块需要暴力的块
	v[id].clear();
	for(int i=L[id];i<=R[id];i++) 
	{
		a[i]=min(a[i],lz[id]);
		if(l<=i&&i<=r)a[i]=min(a[i],x);
		v[id].pb(a[i]);
	}
	sort(v[id].begin(),v[id].end());
}
int ck(int l,int r,int x)//查询区间小于x的数的个数
{
	int id=(l-1)/size+1,ans=0;
//	cout<<l<<"  "<<r<<"  "<<x<<"  "<<id<<"  ====  "<<endl;
	if(L[id]!=l)
	{
		for(int i=l;i<=min(R[id],r);i++)
		{
			a[i]=min(a[i],lz[id]);
			if(a[i]<=x)ans++;
		}
		id++;
	}
//	cout<<ans<<"  "<<"111111"<<endl;
	while(id<=bnm&&R[id]<=r)
	{
		if(lz[id]<=x)ans+=R[id]-L[id]+1;//这里不是+size  因为有一块的大小不等于size 
		else ans+=upper_bound(v[id].begin(),v[id].end(),x)-v[id].begin();
		id++;
	}
	if(id>bnm||L[id]>r)return ans;
	for(int i=L[id];i<=min(r,R[id]);i++)
	{
		a[i]=min(a[i],lz[id ]);
		if(a[i]<=x)ans++;
	}
	return ans;
} 
int qu(int l,int r,int k)//查询区间第k小 
{
	int ans;
	int L=1,R=1e9+7; 
	while(L<=R)
	{
		int mid=(L+R)/2;
		int tp=ck(l,r,mid);
	//	cout<<L<<"  "<<R<<"  "<<tp<<endl;
		if(tp>=k)R=mid-1,ans=mid;
		else L=mid+1;
	}
	return ans;
}
int main()
{
	int n,m;
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++)scanf("%d",&a[i]);
	size=sqrt(n);bnm=(n-1)/size+1;
	//cout<<size<<"  "<<bnm<<endl;
	for(int i=1;i<=bnm;i++)
	{
		L[i]=size*(i-1)+1;
		R[i]=min(size*i,n);
		lz[i]=1e9+1999;
	//	cout<<"--------    "<<L[i]<<"  "<<R[i]<<" "<<i<<" "<<endl;
		for(int j=L[i];j<=R[i];j++)
			v[i].pb(a[j]);
		sort(v[i].begin(),v[i].end());
	}
	while(m--)
	{
		int opt,l,r,x;
		scanf("%d%d%d%d",&opt,&l,&r,&x);
		if(opt==1)up(l,r,x);
		else printf("%d\n",qu(l,r,x));
	}
	return 0;
 } 
发布了284 篇原创文章 · 获赞 13 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/bjfu170203101/article/details/104209283