题目描述
给定一个长度为 NN 的非负整数序列 AA,对于前奇数项求中位数。
输入格式
第一行一个正整数 NN。
第二行 NN 个正整数 A_{1\dots N}A1…N。
输出格式
共(n+1)/2(向下取整) 行,第i行为A1....2i-1的中位数。
说明/提示
对于 20% 的数据,N ≤100;
对于 40% 的数据,N ≤3000;
对于 100% 的数据,1 ≤N≤100000,0≤Ai≤10的九次方
标签:线段树 二分 堆 树状数组(挂的好多啊)
难度:普及/提高-
题目传送门:中位数 - 洛谷
题析
题目很简短,就是给你一个序列,每奇数个数求一次中位数
这个时候我相信大多数人第一想法都是简简单单开开心心每次搞进来两个数sort排序输出中间
这实现起来相当简单
40分代码
#include<bits/stdc++.h>
using namespace std;
long long a[200002],b[200002];
long long n;
int main()
{
ios::sync_with_stdio(0);
cin>>n;
for(int i=1;i<=n;i++)
cin>>a[i];
for(int i=1;i<=n;i+=2)
{
sort(a+1,a+i+1);
cout<<a[(i+1)/2]<< endl;
}
return 0;
}
不放评测记录也都清楚,这种算法是n² log n级别的,肯定超时一大片
那么怎么优化呢?
插入排序固然是有用的,但是经过神犇老师的代码测试,仍然是40分(还不如不写呢)
尽管插入排序把时复降到了n log n的级别,仍然超时一大片
那么,我们就应该寻找时间复杂度为log n的方式
不难想到二分,可是仍然难以实现
这个时候我们就要用到一个神奇的数据结构
它就是vector!(俗称可变数组)
介绍一下它的基本操作(引用洛谷大佬题解、深入浅出)
vc.push_back()在vectorvector末尾插入一个数据
vc.insert()vc.insert()在vectervecter中插入一个元素
vc.erase()vc.erase()在vectorvector中删除一个元素
很棒是不是?完美符合我们的需求
再用upper_bound来二分小于等于该数的数的指针,使得每次插入完都是已经排好序
每次插入后,输出(size()−1)/2即可
AC代码
#include <bits/stdc++.h>
using namespace std;
int n; vector<int>a;//命名vector数组
int main(){
scanf("%d", &n);
for(int i=1, x;i<=n;i++){
scanf("%d", &x);
a.insert(upper_bound(a.begin(),a.end(),x),x);//二分指针所在位置
if(i%2==1)
printf("%d\n",a[(i-1)/2]);
}
return 0;
}
完awa