ZOJ--3612--Median【线段树+离散化】

链接:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=4736

题意:有最多10000次操作,在一个初始为空的数列中添加或移除元素并保持数列有序,每次操作后,如果数列个数为奇数就输出中间值,如果为偶数就输出中间两个值得平均值。

思路:刚开始写了一发multiset模拟,看吴琦TLE了估计他也是multiset写的,就放弃这个思路了,不过最后证明multiset写的机智一点这题也是能过的。线段树、树状数组都考虑了,最后还是用线段树敲了。虽然数字范围是int内,但是操作最多只有10000次,所以需要离散化。先进行离线,再进行离散化,然后建树进行操作。每个节点维护离散化后新的数组对应的下标值在数列中出现了几次。

查询的时候输入要查询数列第几个数,然后从线段树根节点开始递归判断左右子树的数字个数,如果查询的个数小于等于左子树的数字个数,则在左子树中查询,否则要查询的数字减去左子树数字的个数并在右子树中查询,如此递归直到叶子节点,返回节点值,此时返回的值是离散化数组的下标值,再输出答案就好了。

细节: 1.输出比较恶心,对于double类型不输出后导0,直接用cout是可以的,但是输出量太大可能会TLE,所以我转成字符串输出了。

2.虽然数据都在int范围内,但是相加求平均值时可能会溢出,所以用long long来存,因为这个WA了很久。

#include<cstring>
#include<string>
#include<fstream>
#include<iostream>
#include<iomanip>
#include<cstdio>
#include<cctype>
#include<algorithm>
#include<queue>
#include<map>
#include<set>
#include<vector>
#include<stack>
#include<ctime>
#include<cstdlib>
#include<functional>
#include<cmath>
using namespace std;
#define PI acos(-1.0)
#define MAXN 10100
#define eps 1e-7
#define INF 0x7FFFFFFF
#define LLINF 0x7FFFFFFFFFFFFFFF
#define seed 131
#define MOD 1000000007
#define ll long long
#define ull unsigned ll
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1

int sum[MAXN<<2],ans[MAXN],fuck[MAXN],cha[MAXN];
int n,flag;
struct node{
    int num;
    char op;
    int id;
}a[10100];
void pushup(int rt){
    sum[rt] = sum[rt<<1] + sum[rt<<1|1];
}
void build(int l,int r,int rt){
    sum[rt] = 0;
    if(l==r)    return ;
    int m = (l+r)>>1;
    build(lson);
    build(rson);
}
void update(int c,int x,int l,int r,int rt){
    if(l==r){
        if(sum[rt]==0&&x==-1){
            flag = 1;
            return ;
        }
        sum[rt]+=x;
        return ;
    }
    int m = (l+r)>>1;
    if(c<=m)    update(c,x,lson);
    else    update(c,x,rson);
    pushup(rt);
}
int query(int c,int l,int r,int rt){
    if(l==r){
        return l;
    }
    //cout<<sum[rt<<1]<<" "<<l<<endl;
    int m = (l+r)>>1;
    int ret;
    if(sum[rt<<1]>=c){
        ret = query(c,lson);
    }
    else{
        ret = query(c-sum[rt<<1],rson);
    }
    return ret;
}
void output(double x){
    int i;
    char ss[200];
    sprintf(ss,"%lf",x);
    int l = strlen(ss);
    for(i=0;i<l;i++){
        if(ss[i]=='.')  break;
    }
    if(i==l){
        printf("%lf\n",x);
        return ;
    }
    while(ss[l-1]=='0'){
        l--;
    }
    if(ss[l-1]=='.')    l--;
    for(i=0;i<l;i++){
        printf("%c",ss[i]);
    }
    printf("\n");
}
map<int,int>mp;
int main(){
    int i,j,q,t,x;
    char str[20];
    scanf("%d",&t);
    while(t--){
        mp.clear();
        n = 0;
        scanf("%d",&q);
        for(i=1;i<=q;i++){
            scanf("%s%d",str,&a[i].num);
            a[i].op = str[0];
            a[i].id = i;
            fuck[i] = a[i].num;
        }
        sort(fuck+1,fuck+1+q);
        int p = unique(fuck+1,fuck+1+q)-fuck;
        for(i=1;i<p;i++){
            ans[i] = fuck[i];
            mp[fuck[i]] = i;
        }
        j = p;
        build(1,j,1);
        for(i=1;i<=q;i++){
            if(a[i].op=='a'){
                n++;
                update(mp[a[i].num],1,1,j,1);
                if(n%2){
                    printf("%d\n",ans[query(n/2+1,1,j,1)]);
                }
                else{
                    ll temp = 0;
                    temp += ans[query(n/2,1,j,1)];
                    temp += ans[query(n/2+1,1,j,1)];
                    double t2 = temp / 2.0;
                    //printf("%lf\n",t2);
                    output(t2);
                }
            }
            else{
                if(n==0){
                    puts("Wrong!");
                    continue;
                }
                flag = 0;
                update(mp[a[i].num],-1,1,j,1);
                if(flag==1){
                    puts("Wrong!");
                    continue;
                }
                n--;
                if(n==0){
                    puts("Empty!");
                    continue;
                }
                if(n%2){
                    printf("%d\n",ans[query(n/2+1,1,j,1)]);
                }
                else{
                    ll temp = 0;
                    temp += ans[query(n/2,1,j,1)];
                    temp += ans[query(n/2+1,1,j,1)];
                    double t2 = temp / 2.0;
                    //printf("%lf\n",t2);
                    output(t2);
                }
            }
        }
    }
    return 0;
}

/*
10
a 1
a 1000000000
a 1000000000
a -1000000000
a 500
a 60000
r 1000000000
r 1
r 500
a 3000
*/
时间: 2024-11-10 01:35:53

ZOJ--3612--Median【线段树+离散化】的相关文章

ZOJ 3612 Median (multiset)

Median Time Limit: 5 Seconds      Memory Limit: 65536 KB The median of m numbers is after sorting them in order, the middle one number of them if m is even or the average number of the middle 2 numbers if m is odd. You have an empty number list at fi

POJ_2528 Mayor&#39;s poster(线段树+离散化)

题目请点我 题解: 这道题与之前的题目相比重点在于一个映射的预处理,题目所给的区间达到10000000,而最多只有10000个点,如果直接建树的话太过于空旷.把这些区间的左右节点一一对应,最多有4×10000个点,远小于之前的10000000,而且区间之间的对应关系也不会改变. 举个例子: 区间:[2,6],[4,8],[6,10] 我们进行下面对应: 2 4 6 8 10 1 2 3 4 5 则原区间变为[1,3],[2,4],[3,5].可以发现它们之间的覆盖关系并没有改变,但是却紧凑了很多

POJ - 2528 - Mayor&#39;s posters 【线段树+离散化+补点】

http://poj.org/problem?id=2528 #include <cstdio> #include <iostream> #include <set> #include <cstring> #include <string> #define left rt<<1 #define right rt<<1|1 using namespace std; const int MAXN = 32768 + 5; in

HDU5124:lines(线段树+离散化)或(离散化思想)

http://acm.hdu.edu.cn/showproblem.php?pid=5124 Problem Description John has several lines. The lines are covered on the X axis. Let A is a point which is covered by the most lines. John wants to know how many lines cover A. Input The first line conta

hdu1828 Picture(线段树+离散化+扫描线)两种方法

C - Picture Time Limit:2000MS     Memory Limit:10000KB     64bit IO Format:%I64d & %I64u Submit Status Description A number of rectangular posters, photographs and other pictures of the same shape are pasted on a wall. Their sides are all vertical or

Poj 2528 Mayor&#39;s posters (线段树+离散化)

题目连接: http://poj.org/problem?id=2528 题目大意: 有10000000块瓷砖,n张海报需要贴在墙上,每张海报所占的宽度和瓷砖宽度一样,长度是瓷砖长度的整数倍,问按照所给海报顺序向瓷砖上贴海报,最后有几张海报是可见的? 解题思路: 因为瓷砖块数和海报张数多,首选线段树,如果按照常规的建树方式,把瓷砖当做数的节点,肯定会MTL......... 所以我们可以用海报的起点和终点当做树的节点,这样树的节点才有20000个,但是这样建树的话,求海报覆盖了那些节点会很复杂,

hdu 5124 lines (线段树+离散化)

lines Time Limit: 5000/2500 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 620    Accepted Submission(s): 288 Problem Description John has several lines. The lines are covered on the X axis. Let A is a point which

poj2528 线段树+离散化

1 //Accepted 1960K 110MS 2 //线段树+离散化 3 //把所有的坐标排序,从小到大编号,建立线段树 4 #include <cstdio> 5 #include <cstring> 6 #include <iostream> 7 #include <queue> 8 #include <cmath> 9 #include <algorithm> 10 using namespace std; 11 /** 1

POJ 2528 (线段树+离散化) Mayor&#39;s posters

因为将每个单位都作为一个最小单元的话会爆内存的 所以,将海报的每个端点进行排序,将这些端点最为最小的区间. 毕竟是刚刚接触线段树,理解起来还有些吃力,还是那句话,题做多了慢慢就好了. 萌萌的AC代码君贴上. 1 //#define LOCAL 2 #include <iostream> 3 #include <algorithm> 4 #include <cmath> 5 using namespace std; 6 7 int n; 8 struct CPost 9

poj2528--Mayor&#39;s posters(线段树+离散化)

Mayor's posters Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 41785   Accepted: 12164 Description The citizens of Bytetown, AB, could not stand that the candidates in the mayoral election campaign have been placing their electoral post