CSP-J 2021 T2 插入排序(洛谷P7910
CSP-J 2021 T2 插入排序
题目简述
给定一个长度为\(n\)的数列\(a\),需要维护单点修改和冒泡排序后初始数列\(a\)内一元素在更改后的新数组的下标。
思路
首先我们要知道一个小知识,原来有序的数组在经过单点修改后可以用从前往后的冒泡排序加从后往前的冒泡排序各一遍来保持有序,也就是在经过单点修改后我们只需要用\(O(n)\)的时间复杂度来保持数组\(a\)有序。
然后在每次排序之后记录初始a在更改后的新数组的下标,用\(t[a_i]\)来表示初始数列\(a\)中第\(i\)个元素在新数列中的下标,我们就可以实现\(O(1)\)的查询。
因为查询的次数是远远大于更改的次数的,所以我们每次修改完都要排序一遍保持有序。在读入完后要进行一遍排序保证有序。
数列\(a\)用结构体表示,结构体内存储元素的数值和这个元素在初始数列\(a\)中的下标。
代码
点击查看代码
#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
inline int read(){//快读
int x=0,f=1;
char c=getchar();
while(c<'0'||c>'9'){
if(c=='-') f=-1;
c=getchar();
}
while(c>='0'&&c<='9'){
x=(x<<3)+(x<<1)+(c^48);
c=getchar();
}
return x*f;
}
void write(int x){//快写
if(x<0){x=-x;putchar('-');}
if(x>9) write(x/10);
putchar(x%10+'0');
}
struct nums{
int v,pos;
//v是数值,pos是最初的位置
};
int t[8002];
//存储现在的位置
nums b[8002];
bool cmp(nums a,nums b){
if(a.v!=b.v) return a.v<b.v;
return a.pos<b.pos;
//比较大小,因为要一定小于才能换,
//而等于的话就需要看两个元素在初始数列中的位置,
//能不改变前后位置就不改变前后位置
}
int main()
{
int n,q;
n=read();q=read();
for(int i=1;i<=n;++i){
b[i].v=read();b[i].pos=i;
}
sort(b+1,b+1+n,cmp);
//更新位置
for(int i=1;i<=n;++i) t[b[i].pos]=i;
for(int T=1;T<=q;++T){
int op,x;
op=read();x=read();
if(op==1){//单点修改
int v;
v=read();
b[t[x]].v=v;
//冒泡从后往前扫
for(int j=n;j>=2;--j){
if(cmp(b[j],b[j-1])){
nums temp;
temp=b[j];
b[j]=b[j-1];
b[j-1]=temp;
}
}
//冒泡从前往后扫
for(int j=2;j<=n;++j){
if(cmp(b[j],b[j-1])){
nums temp;
temp=b[j];
b[j]=b[j-1];
b[j-1]=temp;
}
}
for(int i=1;i<=n;++i) t[b[i].pos]=i;
//排序完更新现在的位置
}
else if(op==2){
write(t[x]);putchar('\n');
}
}
return 0;
}