权值线段树 洛谷1168
题目描述
给出一个长度为NN的非负整数序列A_iAi,对于所有1 ≤ k ≤ (N + 1) / 21≤k≤(N+1)/2,输出A_1, A_3, …, A_{2k - 1}A1,A3,…,A2k−1的中位数。即前1,3,5,…1,3,5,…个数的中位数。
输入格式
第11行为一个正整数NN,表示了序列长度。
第22行包含NN个非负整数A_i (A_i ≤ 10^9)Ai(Ai≤109)。
输出格式
共(N + 1) / 2(N+1)/2行,第ii行为A_1, A_3, …, A_{2k - 1}A1,A3,…,A2k−1的中位数。
这道题好像不止权值线段树一个做法;
不过本人是用权值线段树来解的,由于数据开到了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 }