版权声明:转载注明出处,谢谢,有问题可以向博主联系 https://blog.csdn.net/VictoryCzt/article/details/84798051
题目地址【IN-luogu】bzoj,loj也有,但是题目可能有点不同,这里的代码是luogu上的AC代码
本来想练练树套树,结果一看数据范围,就试着写了个大力分块,结果过了-_-||,后面再练树套树吧。
对于这几个操作,用分块的话,暴力非常好写:
我们先将原数列分块,对于新的分了块的数列每个快内排个序,复杂度 。
- 查询k在区间内的排名
边角暴力统计,块内二分即可。
- 查询区间内排名为k的值
二分值,然后去统计这个值的排名即可
- 修改某一位值上的数值
在原数组上把它改了,然后将它所在的块还原重新排个序。
- 查询k在区间内的前驱(前驱定义为严格小于x,且最大的数,若不存在输出-2147483647)
边角暴力,块内二分
- 查询k在区间内的后继(后继定义为严格大于x,且最小的数,若不存在输出2147483647)
同理
注意:这里边角暴力时,必须在原数组上查找,不能在排好序的上面找,否则会出错。
复杂度为 卡的过去。
丑陋代码新鲜出炉:
这里我分的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;
}