好久没写题解了,今天肝一篇。
(下午的时候脑袋昏昏沉沉,写题目没有想清楚,竟然被虐了2个小时,心态炸了)
1.审题。
题目很大,你忍一下。
简单地翻译一下题目 。维护一个数组a,a中的所有元素均为非负整数。有两种操作,操作1给出两个数字x,v,意为将修改为v,修改会被保存;操作2给出一个数字,要求输出是a中的第几小,修改不被保存。其中操作1的次数不超过5000次。
此处留下5分钟,诸君先独立思考再看题解——
2.思考算法。
注意红字,操作1的次数不超过5000次。结合n的大小8000,这说明什么?操作1可以使用O(n)的时间复杂度(5e3*8e3=4e7<1e8)!但是,代价为操作2的时间复杂度必须为O(1)或O(logn)。
先思考操作1的O(n)算法。结合题目的背景——插入排序。于是我们可以维护一个结构体b,包含cnt与num两个int类型的数据。其中cnt表示数字大小,num表示这在原来是第几个元素。每次更改数字大小,只要找到满足num==x的b,再进行插入排序,就完美解决了操作1。
不可能,绝对不可能!
的确,我们还没有解决一个问题——遇到两个大小相同的数字怎么办?那么,回想一下,插入排序是怎么排序的——每次处理两个相邻的数字,若与排序顺序相反,则交换。因为插入排序每次只会比较两个相邻的数字,所以不存在两个大小相同的数字,在排序之前与排序之后的相对位置不同的情况,即该算法具有稳定性。
现在,你一定会 茅厕顿开 茅塞顿开。所以num的存储在这里还有一番大用处!对于两个cnt相同的数字,num小的排在前面。即cnt为第一关键字,num为第二关键字。所以,我们的一部分代码就此成型——
……
struct node{
int cnt,num;//已经解释过了
}b[8080];
bool f(node x,node y){//f函数相当于重载了<
return x.cnt==y.cnt ? x.num<y.num : x.cnt<y.cnt;
}
……
for(int i=1;i<=n;i++){
scanf("%d",&b[i].cnt);
b[i].num=i;//初始化成i
}
int op,x,v;
scanf("%d",&op);
if(op==1){//这段代码想必都能看懂
scanf("%d%d",&x,&v);
int i=1;
for(;i<=n;i++) if(b[i].num==x) break;
b[i].cnt=v;
while(i>1){//往前插入
if(f(b[i],b[i-1])){
swap(b[i],b[i-1]);
i--;
}else{
break;
}
}
while(i<n){//往后插入
if(f(b[i+1],b[i])){
swap(b[i],b[i+1]);
i++;
}else{
break;
}
}
}
于是,剩下的一部分也是轻松拿捏——这怎么写O(1)?(被动语态石锤)
显而易见,如果每次输出都要重新查询这个数组,那么整体的时间复杂度就是O(nq),2e5*8e3=1.6e9,超时到了姥姥家。于是,思考一下怎么加快速度。
以寻常的思路,空间换时间——开一个c数组,其中表示第i个数字在排序后的第几个位置(即答案)。那么,在处理b的时候,只需要顺便给c修改一下就可以O(1)回答了。代码(别无脑抄)——
struct ele {
int cnt;
int num;
} b[8080];
int c[8080];
bool f(ele x, ele y) {
return x.cnt == y.cnt ? x.num < y.num : x.cnt < y.cnt;
}
signed main() {
int n, q;
scanf("%d%d", &n, &q);
for (int i = 1; i <= n; i++) {
scanf("%d", &b[i].cnt);
b[i].num = i;
c[i] = i;
}
1.__________;//程序填空1(50分)
for (int i = 1; i <= n; i++) {
c[b[i].num] = i;
}
while (q--) {
int op, x, v;
scanf("%d%d", &op, &x);
if (op == 1) {
scanf("%d", &v);
int t=c[x];//t就是原始位置
2.________;//程序填空2(50分)
while(t>1){
if(f(b[t],b[t-1])){
c[b[t].num]--;
c[b[t-1].num]++;
swap(b[t],b[t-1]);
t--;
}else{
break;
}
}
while(t<n){
if(f(b[t+1],b[t])){
c[b[t].num]++;
c[b[t+1].num]--;
swap(b[t],b[t+1]);
t++;
}else{
break;
}
}//朴实无华
} else {
printf("%d\n", c[x]);//O(1)输出
}
}
}
同时祝愿诸君国庆快乐!