HDU 5249:KPI(权值线段树)
KPI
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)
Problem Description
你工作以后, KPI 就是你的全部了. 我开发了一个服务,取得了很大的知名度。数十亿的请求被推到一个大管道后同时服务从管头拉取请求。让我们来定义每个请求都有一个重要值。我的KPI是由当前管道内请求的重要值的中间值来计算。现在给你服务记录,有时我想知道当前管道内请求的重要值得中间值。
Input
有大约100组数据。
每组数据第一行有一个n(1≤n≤10000),代表服务记录数。
接下来有n行,每一行有3种形式
"in x": 代表重要值为x(0≤x≤109)的请求被推进管道。
"out": 代表服务拉取了管道头部的请求。
"query: 代表我想知道当前管道内请求重要值的中间值. 那就是说,如果当前管道内有m条请求, 我想知道,升序排序后第floor(m/2)+1th 条请求的重要值.
为了让题目简单,所有的x都不同,并且如果管道内没有值,就不会有"out"和"query"操作。
每组数据第一行有一个n(1≤n≤10000),代表服务记录数。
接下来有n行,每一行有3种形式
"in x": 代表重要值为x(0≤x≤109)的请求被推进管道。
"out": 代表服务拉取了管道头部的请求。
"query: 代表我想知道当前管道内请求重要值的中间值. 那就是说,如果当前管道内有m条请求, 我想知道,升序排序后第floor(m/2)+1th 条请求的重要值.
为了让题目简单,所有的x都不同,并且如果管道内没有值,就不会有"out"和"query"操作。
Output
对于每组数据,先输出一行
Case #i:
然后每一次"query",输出当前管道内重要值的中间值。
Case #i:
然后每一次"query",输出当前管道内重要值的中间值。
Sample Input
6
in 874
query
out
in 24622
in 12194
query
Sample Output
Case #1:
874
24622
算法:权值线段树
题解:此题需要先离散化,然后根据权值线段树的特点,依次更新每个区间数的个数,然后根据个数查询即可,题中的拉取了管道头部,直接用队列模拟就好。
#include <iostream> #include <cstdio> #include <vector> #include <queue> #include <algorithm> using namespace std; const int maxn = 1e5+7; struct query { int op; int val; }Q[maxn]; struct tree { int l, r, s; }tree[maxn << 2]; vector<int> v; int n; int len; int find(int x) { return lower_bound(v.begin(), v.end(), x) - v.begin() + 1; } void init() { sort(v.begin(), v.end()); v.erase(unique(v.begin(), v.end()), v.end()); len = v.size(); } void build(int root, int l, int r) { tree[root].l = l; tree[root].r = r; tree[root].s = 0; if(l == r) { return; } int mid = (l + r) >> 1; build(root << 1, l, mid); build(root << 1 | 1, mid + 1, r); } void update(int root, int pos, int val) { int l = tree[root].l; int r = tree[root].r; tree[root].s += val; if(l == r) { return; } int mid = (l + r) >> 1; if(pos <= mid) { update(root << 1, pos, val); } else { update(root << 1 | 1, pos, val); } } int query(int root, int k) { int l = tree[root].l; int r = tree[root].r; if(l == r) { return l; } int sum = tree[root << 1].s; if(sum >= k) { return query(root << 1, k); } else { return query(root << 1 | 1, k - sum); } } int main() { int cas = 0; while(~scanf("%d", &n)) { for(int i = 1; i <= n; i++) { char str[10]; scanf("%s", str); if(str[0] == 'i') { Q[i].op = 1; scanf("%d", &Q[i].val); v.push_back(Q[i].val); } else if(str[0] == 'o') { Q[i].op = 2; } else { Q[i].op = 3; } } init(); build(1, 1, len); queue<int> que; //此队列模拟进出数据 printf("Case #%d:\n", ++cas); for(int i = 1; i <= n; i++) { if(Q[i].op == 1) { int pos = find(Q[i].val); update(1, pos, 1); que.push(pos); } else if(Q[i].op == 2) { update(1, que.front(), -1); que.pop(); } else { int k = (que.size() / 2) + 1; int pos = query(1, k); printf("%d\n", v[pos - 1]); } } } return 0; }