G - Queue HDU - 5493 线段树+二分
G - Queue
题目大意:给你n个人的身高和这个人前面或者后面有多少个比他高的人,让你还原这个序列,按字典序输出。
题解:
首先按高度排序。
设每个人在其前面有k个人,设比这个人高有x个人,所以k=min(k,x-k),求出每一个人在他前面比他高的人的数量。
然后用线段树来维护一段区间的空位,因为对于每一个人来说比他高的人肯定都是出现在他后面,所以这个就说明它前面要空出几个空位。
但是线段树可以维护一段区间的空位,没办法准确找出我需要空位为一个准确的数的位置。
这个就可以二分答案。
要注意几个细节,如果用线段树的话,这个 l 不要从1开始,不然会 T,
然后就是二分这个地方要注意写法,我之前一种写法错了。
#include <cstdio> #include <cstring> #include <cstdlib> #include <queue> #include <stack> #include <vector> #include <algorithm> #define inf 0x3f3f3f3f #define inf64 0x3f3f3f3f3f3f3f3f using namespace std; const int maxn = 1e5 + 10; int ans[maxn]; int n; struct node { int h, k; node(int h = 0, int k = 0) :h(h), k(k) {} }ex[maxn]; bool cmp(node a, node b) { return a.h < b.h; } int sum[maxn * 4]; void push_up(int id) { sum[id] = sum[id << 1] + sum[id << 1 | 1]; } void build(int id, int l, int r) { sum[id] = 0; if (l == r) return; int mid = (l + r) >> 1; build(id << 1, l, mid); build(id << 1 | 1, mid + 1, r); } void update(int id, int l, int r, int pos) { if (l == r) { sum[id] = 1; return; } int mid = (l + r) >> 1; if (pos <= mid) update(id << 1, l, mid, pos); else update(id << 1 | 1, mid + 1, r, pos); push_up(id); } int query(int id, int l, int r, int x, int y) { if (x <= l && y >= r) return r - l + 1 - sum[id]; int mid = (l + r) >> 1; int ans = 0; if (x <= mid) ans += query(id << 1, l, mid, x, y); if (y > mid) ans += query(id << 1 | 1, mid + 1, r, x, y); return ans; } int main() { int t, cnt = 0; scanf("%d", &t); while (t--) { scanf("%d", &n); for (int i = 1; i <= n; i++) { int h, k; scanf("%d%d", &h, &k); ex[i] = node(h, k); } int flag = 0; sort(ex + 1, ex + 1 + n, cmp); for (int i = 1; i <= n; i++) { if (n - i - ex[i].k < 0) flag = 1; ex[i].k = min(ex[i].k, n - i - ex[i].k); } if (flag) { printf("Case #%d: impossible\n", ++cnt); continue; } build(1, 1, n); for (int i = 1; i <= n; i++) { int l = ex[i].k + 1, r = n; while (l <= r) { int mid = (l + r) >> 1; int res = query(1, 1, n, 1, mid); if (res > ex[i].k) r = mid - 1; else l = mid + 1; } ans[r + 1] = ex[i].h; update(1, 1, n, r + 1); } printf("Case #%d:", ++cnt); for (int i = 1; i <= n; i++) printf(" %d", ans[i]); printf("\n"); } return 0; }
#include <cstdio> #include <cstring> #include <cstdlib> #include <queue> #include <stack> #include <vector> #include <algorithm> #define inf 0x3f3f3f3f #define inf64 0x3f3f3f3f3f3f3f3f using namespace std; const int maxn = 1e5 + 10; int ans[maxn]; int n; struct node { int h, k; node(int h = 0, int k = 0) :h(h), k(k) {} }ex[maxn]; bool cmp(node a, node b) { return a.h < b.h; } int sum[maxn]; int lowbit(int x) { return x & (-x); } void update(int i,int k) { while(i<n) { sum[i] += k; i += lowbit(i); } } int getsum(int x) { int res = 0; while(x>0) { res += sum[x]; x -= lowbit(x); } return res; } int main() { int t, cnt = 0; scanf("%d", &t); while (t--) { scanf("%d", &n); for (int i = 1; i <= n; i++) { sum[i] = 0; int h, k; scanf("%d%d", &h, &k); ex[i] = node(h, k); } int flag = 0; sort(ex + 1, ex + 1 + n, cmp); for (int i = 1; i <= n; i++) { if (n - i - ex[i].k < 0) { flag = 1; break; } ex[i].k = min(ex[i].k, n - i - ex[i].k); } if (flag) { printf("Case #%d: impossible\n", ++cnt); continue; } for (int i = 1; i <= n; i++) { int l = ex[i].k + 1, r = n; int num = ex[i].k + 1; while (l <= r) { int mid = (l + r) >> 1; int res = mid - getsum(mid), e = getsum(mid) - getsum(mid - 1); // if (res == num && e == 0) { // ans[mid] = ex[i].h; // update(mid, 1); // flag1 = 1; // break; // } if (res >= num) r = mid - 1; else l = mid + 1; } ans[r + 1] = ex[i].h; update(r + 1, 1); } printf("Case #%d:", ++cnt); for (int i = 1; i <= n; i++) printf(" %d", ans[i]); printf("\n"); } return 0; }