题意:
每组数据第一行有一个n(1≤n≤10000),代表服务记录数。
接下来有n行,每一行有3种形式
“in x”: 代表重要值为x(0≤x≤109)的请求被推进管道。
“out”: 代表服务拉取了管道头部的请求。
"query: 代表我想知道当前管道内请求重要值的中间值. 那就是说,如果当前管道内有m条请求, 我想知道,升序排序后第floor(m/2)+1th 条请求的重要值.
为了让题目简单,所有的x都不同,并且如果管道内没有值,就不会有"out"和"query"操作。
思路:
查询中值,转化为查询第k小,k = 总个数/2 + 1;
离线处理
每次out是把原序列的队头out,所以写一个队列模拟原队列,这样每次都能取到正确的队头元素。
#include <cstdio>
#include <cstring>
#include <algorithm>
#define lson l, mid, rt<<1
#define rson mid+1, r, rt<<1|1
using namespace std;
const int INF = 0x3f3f3f3f;
typedef long long LL;
const int maxn = 10000+5;
int Tree[maxn<<2], X[maxn], que[maxn];
struct querys{
int p, v;
}Q[maxn];
void update(int k, int l, int r, int rt, int val){
Tree[rt]+= val;
if(l == r) return;
int mid = (l+r) >> 1;
if(k <= mid) update(k, lson, val);
else update(k, rson, val);
}
int find_kth(int l, int r, int rt, int k){
if(l == r) return l;
int mid = (l+r) >> 1;
if(Tree[rt<<1] >= k) return find_kth(lson, k);
else return find_kth(rson, k-Tree[rt<<1]);
}
int main()
{
freopen("E:/Cgit/Practice/ACM/in.txt","r",stdin);
int n, kase = 1;
char str[10];
while(scanf("%d",&n) == 1&&n){
printf("Case #%d:\n",kase++);
memset(Tree, 0, sizeof(Tree));
int x, tot = 0;
int front = 0, rear = 0;
for(int i = 1; i <= n; ++i){
scanf("%s", str);
if(str[0] == 'i'){ scanf("%d",&x); Q[i].p = 0; Q[i].v = x; X[++tot] = x; que[rear++] = x;}
else if(str[0] == 'o') Q[i].p = 1;
else Q[i].p = 2;
}
sort(X+1, X+tot+1);
int p, v, k, t;
for(int i = 1; i <= n; ++i){
p = Q[i].p;
v = Q[i].v;
if(p == 0) k = lower_bound(X+1, X+tot+1, v) - X;
else if(p == 1) k = lower_bound(X+1, X+tot+1, que[front++]) - X;
switch(p){
case 0: update(k, 1, n, 1, 1); break;
case 1: update(k, 1, n, 1, -1); break;
case 2: t = find_kth(1, n, 1, Tree[1]/2+1);
printf("%d\n", X[t]);
}
}
}
return 0;
}