Ac.Wing 106 动态中位数(Offline)

题解:
这个题目和之前的邻值查找问题很相似,这个题关键就是在于弄清楚链表中中位数到底是如何变化的。
我们简单分析一下这个题目:
动态取值,动态取出中位数,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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

CUCKyrie

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值