码迷,mamicode.com
首页 > 其他好文 > 详细

POJ 3784 Running Median (动态中位数)

时间:2015-07-17 11:58:06      阅读:130      评论:0      收藏:0      [点我收藏+]

标签:

题目链接:http://poj.org/problem?id=3784

题目大意:依次输入n个数,每当输入奇数个数的时候,求出当前序列的中位数(排好序的中位数)。

  此题可用各种方法求解。

  排序二叉树方法,每个结点保存以其为根的左右子树中数的个数。如果数据出的够严格,这种方法会被卡的,除非是通过动态调整维持树的高度较小。

  排序二叉树的代码如下:

技术分享
#include <cstdio>
using namespace std;
#define N 20000

struct Node {
    int v;
    Node *lc, *rc;//左子树、右子树
    int ln, rn;//左右子树下保存数的个数
};

Node* Tr;//树根


void insert(Node *&T, int v)//注意T要引用
{
    if(T==NULL)
    {
        T = new Node();
        T->v = v;
        T->lc = T->rc = NULL;
        T->ln = T->rn = 0;
        return;
    }
    if(v <= T->v)
    {
        insert(T->lc, v);
        T->ln++;
    }
    else
    {
        insert(T->rc, v);
        T->rn++;
    }
}

int query(Node *T, int c)
{
    int num = T->ln;
    if(c == num+1) return T->v;
    if(c < num+1) return query(T->lc, c);
    else return query(T->rc, c-num-1);
}

int ans[N];
int main()
{
    int T, cas, n, v;
    scanf("%d", &T);
    while(T--)
    {
        int c = 0;
        Tr = NULL;
        scanf("%d %d", &cas, &n);
        for(int i = 0; i < n; i++)
        {
            scanf("%d", &v);
            insert(Tr, v);
            if(i % 2 == 0) ans[c++] = query(Tr, (i+2)/2);
        }

        printf("%d %d\n", cas, (n+1)/2);
        printf("%d",ans[0]);
        for(int i = 1; i < c; i++)
        {
            if(i%10==0)puts("");
            else printf(" ");
            printf("%d", ans[i]);
        }
        if(c % 10 != 0) puts("");
    }
    return 0;
}
View Code

  堆方法,维护两个堆,一个大顶堆,一个小顶堆,大顶堆保存较小的一半数,小顶堆保存较大的一半数,任何时刻,任何时刻,保证大顶堆中元素的个数比小顶堆中的元素个数多1或相等,则大顶堆的堆顶元素就是中位数,代码如下:

技术分享
#include <cstdio>
#include <algorithm>
using namespace std;
#define N 20000

int smaq[N], bigq[N];

bool cmp(int a, int b){
    return a > b;
}

int ans[N];
int main()
{
    int T, cas, n, v;
    scanf("%d", &T);
    while(T--)
    {
        int c = 0;
        scanf("%d %d", &cas, &n);
        int t1 = 0, t2 = 0;
        for(int i = 0; i < n; i++)
        {
            scanf("%d", &v);
            if(t1 == 0 || bigq[0] >= v) bigq[t1++] = v;
            else smaq[t2++] = v;
            push_heap(bigq, bigq+t1);
            push_heap(smaq, smaq+t2, cmp);
            
            if(t1-t2 == 2)
            {
                pop_heap(bigq, bigq+t1);
                smaq[t2++] = bigq[--t1];
                push_heap(smaq, smaq+t2, cmp);
            }
            else if(t2-t1 == 1)
            {
                pop_heap(smaq, smaq+t2, cmp);
                bigq[t1++] = smaq[--t2];
                push_heap(bigq, bigq+t1);
            }
            if(i % 2 == 0) ans[c++] = bigq[0];
        }
        printf("%d %d\n", cas, (n+1)/2);
        printf("%d",ans[0]);
        for(int i = 1; i < c; i++)
        {
            if(i%10==0)puts("");
            else printf(" ");
            printf("%d", ans[i]);
        }
        if(c % 10 != 0) puts("");
    }
    return 0;
}
View Code

  线段树方法,先将所有数据读入,做离散化,这样,每个数插入的时候直接插入到其应该去的位置上(排好序的下标),就可以用线段树了。

技术分享
#include <cstdio>
#include <algorithm> 
#include <cstring>
using namespace std;
#define N 20000

int tr[N<<2];//线段树 

void insert(int id, int l, int r, int pos)//在一个位置插入 
{
    tr[id]++;
    if(l == r) return ;
    int lc = id<<1, rc = (id<<1)|1, mid = (l+r)>>1;
    if(pos <= mid) insert(lc, l, mid, pos);
    else insert(rc, mid+1, r, pos);
}

int query(int id, int l, int r, int c)//查询第c个数 
{
    if(l == r) return l;
    int lc = id<<1, rc = (id<<1)|1, mid = (l+r)>>1;
    if(tr[lc] >= c) return query(lc, l, mid, c);
    else return query(rc, mid+1, r, c-tr[lc]);
}

int ans[N];
int sq[N], sortsq[N];


int find(int l, int r, int v)
{
    while(l <= r)
    {
        int mid = (l+r)>>1;
        if(v == sortsq[mid]) return mid;
        else if(v < sortsq[mid]) r = mid-1;
        else l = mid+1;
    }
}

int main()
{
    int T, cas, n, v;
    scanf("%d", &T);
    while(T--)
    {
        memset(tr, 0, sizeof(tr)); 
        int c = 0;
        scanf("%d %d", &cas, &n);
        for(int i = 0; i < n; i++) scanf("%d", &sq[i]);
        memcpy(sortsq, sq, sizeof(sq));
        sort(sortsq, sortsq+n);
        //for(int i = 0; i < n; i++) printf("%d ", sortsq[i]); puts(""); 
            
        for(int i = 0; i < n; i++)
        {
            int id = find(0, n-1, sq[i]);
            insert(1, 0, n-1, id);
            if(i%2 == 0) 
            //printf("id = %d\n", query(1, 0, n-1, (i+2)/2));
            ans[c++] = sortsq[query(1, 0, n-1, (i+2)/2)];
        }
        //for(int i = 1; i <= 2*n; i++)printf("%d ", tr[i]); puts("");
        printf("%d %d\n", cas, (n+1)/2);
        printf("%d",ans[0]);
        for(int i = 1; i < c; i++)
        {
            if(i%10==0)puts("");
            else printf(" ");
            printf("%d", ans[i]);
        }
        if(c % 10 != 0) puts("");
        
    }
    return 0;
}
View Code

 

POJ 3784 Running Median (动态中位数)

标签:

原文地址:http://www.cnblogs.com/beisong/p/4653818.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!