块内打个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;
}