题目描述

给出一个长度为NN的非负整数序列A_iAi,对于所有1 ≤ k ≤ (N + 1) / 21k(N+1)/2,输出A_1, A_3, …, A_{2k - 1}A1,A3,,A2k1的中位数。即前1,3,5,…1,3,5,…个数的中位数。

输入格式

11行为一个正整数NN,表示了序列长度。

22行包含NN个非负整数A_i (A_i ≤ 10^9)Ai(Ai109)。

输出格式

(N + 1) / 2(N+1)/2行,第ii行为A_1, A_3, …, A_{2k - 1}A1,A3,,A2k1的中位数。

这道题好像不止权值线段树一个做法;

不过本人是用权值线段树来解的,由于数据开到了1e9,所以得离散化。

在权值线段树里,叶子节点是1代表的数字是1,2是2,3是3,以此类推,其父亲节点是包含这一区间内的数;

离散化之后,先build,记录每一个节点的所包含的数字大小范围,

然后在慢慢建树,建树的过程中,当单数的时候,就进行查询;

 1 #include<cstdio>
 2 #include<algorithm>
 3 #include<math.h>
 4 #include<string.h>
 5 #include<queue>
 6 using namespace std;
 7 const int maxn=1e5+10;
 8 int a[maxn],b[maxn];
 9 struct node
10 {
11     int l,r,mid;
12     int num;
13 }tree[maxn<<2];
14 void build(int l,int r,int cur)
15 {
16     tree[cur].l=l,tree[cur].r=r;
17     tree[cur].num=0;
18     tree[cur].mid=(l+r)/2;
19     if(l==r) return;
20     build(l,tree[cur].mid,cur<<1);
21     build(tree[cur].mid+1,r,cur<<1|1);
22 }
23 void update(int pos,int cur)
24 {
25     tree[cur].num++;
26     if(tree[cur].l==tree[cur].r) return;
27     if(pos<=tree[cur].mid)
28         update(pos,cur<<1);
29     else update(pos,cur<<1|1);
30 }
31 int query(int base,int cur)
32 {
33     if(tree[cur].l==tree[cur].r) return tree[cur].l;
34     if(base<=tree[cur<<1].num) return (query(base,cur<<1));
35     else return (query(base-tree[cur<<1].num,cur<<1|1));
36 }
37 int main()
38 {
39     int n;
40     scanf("%d",&n);
41     for(int i=1;i<=n;i++){
42         scanf("%d",&a[i]);
43         b[i]=a[i];
44     }
45     sort(b+1,b+1+n);
46     int t=unique(b+1,b+1+n)-b-1;
47     build(1,n,1);
48     for(int i=1;i<=n;i++){
49         int pos=lower_bound(b+1,b+1+t,a[i])-b;
50         update(pos,1);
51         if(i%2) printf("%d\n",b[query(i/2+1,1)]);
52     }
53     return 0;
54 }