ZOJ3612 Median

http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=3612

题意:对一集合有addxremovex两种操作。输出每次操作后该集合的中位数。

解法:用set来维护这个集合,同时用一指针指向每个时刻中位数。注意multiset每次查找后迭代器指向相同元素的第一个而且删除迭代器指向的元素后迭代器就不知道指向哪儿了。所以要记得保存迭代器信息,和数组不一样不会下一个元素不会前移。

addremove元素时,对于集合元素个数的奇偶性和要操作的元素和当前所指元素的大小关系可以方便得到指针的移动规律。


这种做法比线段树做法在查找时提高了效率,从O(logn)降到了O(1):


时间790ms效果明显。


#include <cstdio>
#include <cstring>
#include <cmath>
#include <map>
#include <set>
#include <vector>
#include <iostream>
#include <algorithm>
using namespace std;
const double eps=1e-7;
const double INF=1e50;
const double pi=acos(-1);

#define N 15

int main()
{
    //freopen("a","r",stdin);

    int i,j,b,t,n,as;
    char s[10];
    multiset<int> a;

    scanf("%d",&t);

    for (int kk=1;kk<=t;kk++)
    {
        a.clear();
        scanf("%d",&n);
        multiset<int>::iterator it;
        multiset<int>::iterator it1;
        multiset<int>::iterator it2;

        for (i=1;i<=n;i++)
        {
            scanf("%s %d",s,&b);
            if (s[0]=='a')
            {
               a.insert(b);

               if (a.size()==1) it1=a.begin();
               else
               {
                   if ((a.size()%2-1)!=0 && b<*it1) it1--;
                   if ((a.size()%2-1)==0 && b>=*it1) it1++;
               }
            }
            else if (s[0]=='r')
            {
                 it=a.find(b);
                 if (it==a.end())
                 {
                    printf("Wrong!\n");
                    continue;
                 }
                 else
                 {
                      if (*it1==b)
                      {
                         it=it1;//就删所指向的那个元素,比较方便

                         if (a.size()%2==0) it1++;
                         else it1--;
                      }
                      else
                      {
                          if (a.size()%2!=0 && b>*it1) it1--;
                          if (a.size()%2==0 && b<*it1) it1++;
                      }

                      a.erase(it);//先复制信息后操作
                 }
            }

            j=a.size();
            if (j==0) printf("Empty!\n");
            else
            {
                if (j%2!=0) printf("%d\n",*it1);
                else
                {
                    it2=it1;
                    it2++;

                    long long j2=(long long)*it1+(long long)*it2;
                    if (j2%2==0) printf("%lld\n",j2/2);
                    else if (j2==-1) printf("-0.5\n");
                    else printf("%lld.5\n",j2/2);
                }
            }
        }
    }

    return 0;
}





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值