蓝桥杯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;
}