蓝桥杯—第几小

蓝桥杯2022省赛题——第几小。本体的解题思路是采用分块算法降低时间复杂度,但我最后只通过19个样例,还剩一个。可能是分块的长度不是最佳的,再调一下长度说不定能pass
题目

#include <iostream>
#include <vector>
#include <cmath>
#include <algorithm>
using namespace std;
int main()
{
  // 请在此输入您的代码
  int n;
	cin>>n;
  //块长
  int len=sqrt(n)*log(n)/2;
  //块数
  int k=(n%len==0)?n/len:n/len+1;
  //分块
  vector<int> block[k+1];
  //第i个数属于的块
  vector<int> belong(n+1,0);
	vector<int> a(n+1,0);
  int blockNum=0;
	for(int i=1;i<=n;i++){
		cin>>a[i];
    blockNum=(i-1)/len+1;
    belong[i]=blockNum;
    block[blockNum].push_back(a[i]);
	}
  //对分块进行排序
  for(int i=1;i<=k;i++){
    sort(block[i].begin(),block[i].end(),less<int>());
  }
  //记录操作
	int m;
	cin>>m;
	vector<vector<int>> op(m,vector<int>(4,0));
	for(int i=0;i<m;i++){
		 cin>>op[i][0];
		 if(op[i][0]==1){
			//修改操作
			for(int j=1;j<=2;j++){
				cin>>op[i][j];
			}		 	
		 }else{
		 	//查询操作
			 for(int j=1;j<=3;j++){
			 	cin>>op[i][j];
			 } 
		 }
	}
  //执行操作
	vector<int> res;
	int num1,num2,num3;
	num1=num2=num3;
	int count=0;
  int mid=0;
	for(int i=0;i<m;i++){
		num1=op[i][1];
		num2=op[i][2];
		num3=op[i][3];
		if(op[i][0]==1){
      //修改分组
      auto it=lower_bound(block[belong[num1]].begin(),block[belong[num1]].end(),a[num1]);
      block[belong[num1]].erase(it);
      it=lower_bound(block[belong[num1]].begin(),block[belong[num1]].end(),num2);
      if(it==block[belong[num1]].end()){
        block[belong[num1]].push_back(num2);
      }else{
        block[belong[num1]].insert(it,num2);
      }
      //修改原序列
			a[num1]=num2;
		}else{
      count=0;
      mid=a[num3];
      //先查左右两端分块中满足条件的元组数,因为num1和num2所在的块不一定一整块都参与比较
      for(int j=num1;j<=min(num2,belong[num1]*len);j++){
        if(a[j]<mid){
          count++;
        }
      }
      if(belong[num1]!=belong[num2]){
        for(int j=(belong[num2]-1)*len+1;j<=num2;j++){
          if(a[j]<mid){
            count++;
          }
        }
      }
      //区间查询,用二分法查询每个块中小于a[p]的元素个数
      for(int j=belong[num1]+1;j<=belong[num2]-1;j++){
        count+=lower_bound(block[j].begin(),block[j].end(),a[num3])-block[j].begin();
      }
      res.push_back(count+1);
      //49 31 31 11 24 8 4 62 7 11 46 47 3 20 16 24 29 11 2 4 5 16 3 68 
		}
	}
	for(auto &&num:res){
		cout<<num<<" ";
	}
  return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值