Solution

分析题意,要求我们求出每一个奇数长度前缀的中位数
对于每一个奇数长度前缀,设长度为len,求中位值其实就是求区间第(len + 1) / 2大
那么显然这就是一道求区间第k大的模板题了
我们直接上主席树,秒掉这个问题
这里简单介绍下主席树
主席树又叫可持久化线段树,它是基于线段树发展而来的一种数据结构。
给线段树增加一些历史点来维护历史数据,使得我们能在较短时间内查询历史数据。
主席树思想是每个位置都维护一个线段树,线段树的节点是值的范围。
然后第i个线段树中某个区间[x, y]维护的是,1-i中数字在[x, y]范围内的个数。
因此我们运用前缀和的思想,在主席树上二分递归求解即可求出区间第k大。
注意数据范围,需要先离散化。
时间复杂度大概是?

Code

#pragma GCC optimize(3)
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef long long LL;
const int N = 1e5 + 5;
const ll mod = 7;
const int DEG = 20;
const double PI = acos(-1.0);
const double eps = 1e-10;
const ll inf = 1e18;
static auto faster_iostream = []() {
    std::ios::sync_with_stdio(false);  // turn off sync
    std::cin.tie(nullptr);             // untie in/out streams
    return 0;
}();
int n, q, m, tot;
int a[N], t[N];
int T[N], lson[N * 50], rson[N * 50], c[N * 50];
void Init_hash(){
  for(int i = 1; i <= n; i++){
    t[i] = a[i];
  }
  sort(t + 1, t + 1 + n);
  m = unique(t + 1, t + 1 + n) - t - 1;
}
int Hash(int x){
  return lower_bound(t + 1, t + 1 + m, x) - t;
}
int build(int l, int r){
  int root = tot++;
  c[root] = 0;
  if(l != r){
    int mid = l + r >> 1;
    lson[root] = build(l, mid);
    rson[root] = build(mid + 1, r);
  }
  return root;
}
int Insert(int root, int pos, int val){
  int newroot = tot++, tmp = newroot;
  c[newroot] = c[root] + val;
  int l = 1, r = m;
  while(l < r){
    int mid = l + r >> 1;
    if(pos <= mid){
      lson[newroot] = tot++, rson[newroot] = rson[root];
      newroot = lson[newroot], root = lson[root];
      r = mid;
    }
    else {
      rson[newroot] = tot++, lson[newroot] = lson[root];
      newroot = rson[newroot], root = rson[root];
      l = mid + 1;
    }
    c[newroot] = c[root] + val;
  }
  return tmp;
}
int Query(int left_root, int right_root, int k){
  int l = 1, r = m;
  while(l < r){
    int mid = l + r >> 1;
    int tmp = c[lson[left_root]] - c[lson[right_root]];
    if(tmp >= k){
      r = mid;
      left_root = lson[left_root];
      right_root = lson[right_root];
    }
    else {
      l = mid + 1;
      k -= tmp;
      left_root = rson[left_root];
      right_root = rson[right_root];
    }
  }
  return l;
}
int main(){
  int Tcase;
  cin >> Tcase;
  int cas = 0;
  while(Tcase--){
    tot = 0;
    ++cas;
    int p;
    cin >> p;
    cin >> n;
    for(int i = 1; i <= n; i++) cin >> a[i];
    Init_hash();
    T[n + 1] = build(1, m);
    for(int i = n; i; i--){
      int pos = Hash(a[i]);
      T[i] = Insert(T[i + 1], pos, 1);
    }
    vector<int> v;
    for(int i = 1; i <= n; i += 2){
      v.push_back(t[Query(T[1], T[i + 1], (i + 1) / 2)]);
    }
    cout << cas << ' ' << v.size() << "\n";
    for(int i = 0; i < v.size(); i++){
      if(i && i % 10 == 0){
        cout << "\n";
      }
      cout << v[i] << " \n"[i == v.size() - 1];
    }
  }
  return 0;
}