维护序列的动态中位数
第一次用链表做题。。感觉指针指来指去也挺麻烦的。。
本题链表解法就是用数组模拟出一个链表,然后离线输入所有数,排序,按照输入顺序在链表里删除元素,一次性删掉两个,然后中位数指针对应移动即可
#include<iostream> #include<cstring> #include<cstdio> #include<algorithm> using namespace std; #define maxn 10004 struct smc{ int val,no; bool operator<(smc node)const{ return val<node.val; } }a[maxn]; int l[maxn],r[maxn],tt,p,n,mid; int ans[maxn],f[maxn]; int main(){ scanf("%d",&p); for(tt=1;tt<=p;tt++){ scanf("%d%d",&mid,&n); printf("%d %d ",tt, n/2+1); mid=(1+n)/2; for(int i=1;i<=n;i++){scanf("%d",&a[i].val);a[i].no=i;} sort(a+1,a+1+n); for(int i=1;i<=n;i++){l[i]=i-1;r[i]=i+1;f[a[i].no]=i;} l[0]=l[1]=100,r[0]=1; for(int i=n;i>=1;i-=2){//一次减掉两个数 ans[i]=a[mid].val; if(f[i]<mid && f[i-1]<=mid) mid=r[mid]; if(f[i]>mid && f[i-1]>=mid) mid=l[mid]; if(f[i]==mid){ if(f[i-1]>mid) mid=l[mid]; else mid=r[mid]; } //从链表中删去这两个结点 r[l[f[i]]]=r[f[i]]; l[r[f[i]]]=l[f[i]]; r[l[f[i-1]]]=r[f[i-1]]; l[r[f[i-1]]]=l[f[i-1]]; } int cnt=0; for(int i=1;i<=n;i+=2){ printf("%d ",ans[i]); if(++cnt>=10) puts(""),cnt=0; } puts(""); } return 0; }
网上另外一种解法是对顶堆,所谓对顶堆,就是建立一个小根堆q1,大根堆q2,每次读入的数如果比中位数大,那么就把它放入小根堆中,反之放入大根堆中,小根堆元素必须等于大根堆或者是大根堆+1,如果不符合要求就调整,小根堆堆顶元素即是中位数
hdu和poj输出方式有点不一样
#include<bits/stdc++.h> #define maxn 10005 using namespace std; priority_queue<int,vector<int>,greater<int> >q1;//小根堆,堆顶中位数 priority_queue<int,vector<int>,less<int> >q2;//、大根堆 int T,n,x,cnt,tot,ans[maxn]; void add(int x){ if(q1.empty()){ q1.push(x); return; } if(x>q1.top()) q1.push(x); else q2.push(x); while(q1.size()<q2.size()){ q1.push(q2.top()); q2.pop(); } while(q1.size()>q2.size()+1){ q2.push(q1.top()); q1.pop(); } } int main(){ scanf("%d",&T); for(int tt=1;tt<=T;tt++){ scanf("%d%d",&tt,&n); printf("%d %d ",tt,n/2+1); while(!q1.empty())q1.pop(); while(!q2.empty())q2.pop(); cnt=tot=0; for(int i=1;i<=n;i++){ scanf("%d",&x); add(x); if(i%2!=0) ans[tot++]=q1.top(); } for(int i=0;i<tot;i++){ if(i>0 && i%10==0) puts(""); if(i%10) putchar(' '); printf("%d",ans[i]); } puts(""); } return 0; }