poj 2828 Buy Tickets(树状数组 | 线段树)

题目链接:poj 2828 Buy Tickets

题目大意:给定N,表示有个人,给定每一个人站入的位置,以及这个人的权值,如今按队列的顺序输出每一个人的权值。

解题思路:第K大元素,非常巧妙,将人入队的顺序倒过来看,就是纯第K大问题,然后用树状数组还是线段树就都能够做了。

C++ 线段树
#include <cstdio> #include <cstring> #include <algorithm> using namespace std; const int maxn = 200005; #define lson(x) ((x)<<1) #define rson(x) (((x)<<1)+1) struct Node { int l, r, s; void set(int l, int r, int s) { this->l = l; this->r = r; this->s = s; } }nd[maxn * 4]; int N, val[maxn], pos[maxn], rec[maxn]; void build (int u, int l, int r) { nd[u].set(l, r, r - l + 1); if (l == r) return ; int mid = (l + r) / 2; build(lson(u), l, mid); build(rson(u), mid + 1, r); } int query (int u, int x) { nd[u].s--; if (nd[u].l == nd[u].r) return nd[u].l; if (nd[lson(u)].s >= x) return query(lson(u), x); else return query(rson(u), x - nd[lson(u)].s); } int main () { while (scanf("%d", &N) == 1) { build(1, 0, N - 1); for (int i = 0; i < N; i++) scanf("%d%d", &pos[i], &val[i]); for (int i = N - 1; i >= 0; i--) rec[query(1, pos[i] + 1)] = i; printf("%d", val[rec[0]]); for (int i = 1; i < N; i++) printf(" %d", val[rec[i]]); printf("\n"); } return 0; }
C++ 树状数组
#include <cstdio> #include <cstring> #include <algorithm> using namespace std; const int maxn = 200005; #define lowbit(x) ((x)&(-x)) int N, fenw[maxn], pos[maxn], val[maxn], rec[maxn]; void add (int x, int v) { while (x <= N) { fenw[x] += v; x += lowbit(x); } } int find (int x) { int p = 0, s = 0; for (int i = 20; i >= 0; i--) { p += (1<<i); if (p > N || s + fenw[p] >= x) p -= (1<<i); else s += fenw[p]; } return p + 1; } int main () { while (scanf("%d", &N) == 1) { memset(fenw, 0, sizeof(fenw)); for (int i = 1; i <= N; i++) { add(i, 1); scanf("%d%d", &pos[i], &val[i]); } for (int i = N; i; i--) { int tmp = find(pos[i] + 1); rec[tmp] = i; add(tmp, -1); } for (int i = 1; i <= N; i++) printf("%d%c", val[rec[i]], i == N ? '\n' : ' '); } return 0; }

posted @ 2015-01-31 14:05  mfrbuaa  阅读(228)  评论(0编辑  收藏  举报