题解:
这个题目和之前的邻值查找问题很相似,这个题关键就是在于弄清楚链表中中位数到底是如何变化的。
我们简单分析一下这个题目:
动态取值,动态取出中位数,Online做法是使用大小堆,但是这里因为刚学了链表其实是不会大小堆orz我们就用Offline的方法写了。
首先我们把所有的数据加入链表并排序,记录一下他们在原链表中的位置和现在的位置,我们仍然是和136题一样采用从后取值的方式,对于第n
个数据,答案肯定是
a
[
(
n
+
1
)
/
2
]
a[(n + 1 ) / 2]
a[(n+1)/2],我们知道它只有在链表长度为奇数时才会输出中位数,那么就相当于每删除两次数据中位数才有可能发生变化,根据两次选取数据的不同我们就可以找出对应中位数的变化。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<set>
#include<bitset>
#include<queue>
#include<map>
#include<vector>
#define ll long long
#define inf -1e12
#define INF 1e12
#define ios std :: ios :: sync_with_stdio(false)
#define PII pair<ll ,ll>
using namespace std;
const int maxn = 1e4 + 19;
PII a[maxn];
vector<ll > ans;
map<ll,ll> mp,l,r;
int main()
{
ios;
int p;
cin >> p;
while(p--){
ans.clear();
int Case,n;
cin >> Case >> n;
for(int i = 1;i <= n;i++) {
ll x;
cin >> x;
a[i].first = x;
a[i].second = i;
}
sort(a + 1,a + 1 + n);
a[0] = {inf,0};
a[n + 1] = {INF,n + 1};
for(int i = 1;i <= n;i++) {
ll x = a[i].second;
l[i] = i - 1;
r[i] = i + 1;
mp[x] = i;
}
int now = (n + 1) / 2;
for(int i = n;i >= 1;i--){
int it = mp[i],left = l[it],right = r[it];
// cout << "it = " << it << endl;
// cout << left << ' ' << right << endl;
if(i % 2 == 1) {
ans.push_back(a[now].first);
if(it <= now) now = r[now];
}
else if(it >= now) now = l[now];
r[left] = right;
l[right] = left;
}
cout << Case << ' ' << (n + 1) / 2 << endl;
std::reverse(ans.begin(),ans.end());
for(int i = 0;i < ans.size();i++){
if((i + 1) % 10 == 0 && i < ans.size() - 1){
cout << ans[i];
cout << endl;
}
else if(i == ans.size() - 1) cout << ans[i] << endl;
else cout << ans[i] << ' ';
}
}
return 0;
}