题意就是有大约1-10000个操作,每次插入或者删除一个数,每次操作后的中位数都要输出
然后思路就比较清晰了, 先把数据都读进来,所有的数存起来离散化,然后再处理每个操作,每次维护树状数组即可,然后如果整个序列有奇数个,就直接二分找最中间的,如果偶数个就找两个数。
这题比较恶心的就是输出了。用cout按理说最好了,但是会超时,用long long的话,除以2的时候判奇数输出.5也会挂,除非转换成double然后%.1f不会挂,这一点很费解啊。当然直接用double转化为字符串是不可能挂的。
保险点用double 吧
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#define MAXN 10005
#define MAXM 1000005
#define INF 1000000000
#define eps 1e-6
using namespace std;
int op[MAXN];
int n, a[MAXN], t[MAXN];
double x[MAXN], num[MAXN];
int lowbit(int x)
{
return x & -x;
}
void modify(int x, int v)
{
for(int i = x; i <= n; i += lowbit(i))
a[i] += v;
}
int getsum(int x)
{
int sum = 0;
for(int i = x; i > 0; i -= lowbit(i))
sum += a[i];
return sum;
}
int find(double val, int low, int high)
{
while(low <= high)
{
int mid = (low + high) >> 1;
if(fabs(x[mid] - val) < eps) return mid;
if(x[mid] > val) high = mid - 1;
else low = mid + 1;
}
return -1;
}
int median(int val, int low, int high)
{
while(low <= high)
{
int mid = (low + high) >> 1;
int sum = getsum(mid);
if(sum >= val) high = mid - 1;
else low = mid + 1;
}
return low;
}
void output(double val)
{
if(floor(val) == val)
printf("%.0f\n", val);
else
{
char s[55];
sprintf(s, "%f", val);
int len = strlen(s);
int pos = len - 1;
for(int i = len - 1; i >= 0; i--)
{
if(s[i] != '0' || i == 0)
{
pos = i;
break;
}
}
for(int i = 0; i <= pos; i++) putchar(s[i]);
putchar('\n');
}
}
int main()
{
int T;
char s[22];
scanf("%d", &T);
while(T--)
{
scanf("%d", &n);
for(int i = 1; i <= n; i++)
{
scanf("%s%lf", s, &num[i]);
if(s[0] == 'r') op[i] = 0;
else op[i] = 1;
x[i] = num[i];
}
sort(x + 1, x + n + 1);
int f = n;
n = unique(x + 1, x + n + 1) - x - 1;
memset(a, 0, sizeof(a));
memset(t, 0, sizeof(t));
for(int i = 1; i <= f; i++)
{
if(op[i])
{
int pos = find(num[i], 1, n);
modify(pos, 1);
t[pos]++;
int len = getsum(n);
if(len % 2 == 1)
{
double k = x[median(len / 2 + 1, 1, n)];
output(k);
}
else
{
double k1 = x[median(len / 2, 1, n)];
double k2 = x[median(len / 2 + 1, 1, n)];
output((k1 + k2) / 2);
}
}
else
{
int pos = find(num[i], 1, n);
if(t[pos] < 1) printf("Wrong!\n");
else
{
t[pos]--;
modify(pos, -1);
int len = getsum(n);
if(len == 0) printf("Empty!\n");
else if(len % 2 == 1)
{
double k = x[median(len / 2 + 1, 1, n)];
output(k);
}
else
{
double k1 = x[median(len / 2, 1, n)];
double k2 = x[median(len / 2 + 1, 1, n)];
output((k1 + k2) / 2);
}
}
}
}
}
return 0;
}
分享到:
相关推荐
因为子树树形被破坏,在做减法时,子节点子树对父节点的贡献不能用子树维护的信息 + 连向父节点的边的贡献得到,考虑在每个节点再维护一个线段树,按距离建树用来统计子树内的节点到其父节点距离为 p 的点权和,这样...
ZOJ解题报告ZOJ解题报告ZOJ解题报告ZOJ解题报告
ZOJ1007 计算形如sigma(1/(k(k+x)),1,+OO)的近似数值。
zoj题目简单归类zoj题目简单归类zoj题目简单归类
acm中zoj1002的可运行C++程序
包含了zoj700多道题目的源代码,在做题时可以参考
Problem Arrangement zoj 3777
ZOJ题目答案源码
zoj 3212 K-Nice.md
学习ACM程序设计的朋友一定要看,这是训练必备的POJ ZOJ题目分类及解题思路
一个非常非常非常非常实用的zoj结题代码
zoj 1003 c语言的,要写这么多描述吗。。
浙大ZOJ题目分类,可以让你更方便快速锁定那你想要联系的题目,是自己快速提高·
ZOJ1805代码
本代码是zoj上AC的1951的代码,把双重循环简化为O(n),不过素数判断的改进还不够
zoj1027解题指南和代码,还不错,是学校培训给的。
ZOJ题解集合-截至2835。共1244个文件,C/C++,有重复
zoj 题库 详细解答 解题代码 acm
zoj4041正确题解源代码,以及运行程序
zoj吐血制作,希望大家喜欢