HDU - 5493 Queue(二分+樹狀陣列)
阿新 • • 發佈:2018-11-17
題目連結:傳送門
題意:給你n個人,知道每個人的身高和每個人的前面或者後面有多少個比他高的,讓你輸出字典序最小的可能的排序。
思路:我們可以將人按身高升序順序,然後模擬插空,因為這樣我們就能保證之後插入的人有位置可插,只要注意每次我們可以判斷需要插入的空位置=min(k,n-i-k)。(i為第i個人,k為第i個人有k個比他高的),如果小於0(代表n-i-k<0,空位置小於k個),則就是不可能的,然後只要二分去找位置,用樹狀陣列更新就行了。
附上程式碼:
#include<cstdio> #include<cmath> #include<algorithm> #include<cstring> #include<string> #include<iostream> #include<map> #include<vector> #include<set> #include<queue> using namespace std; const int inf = 0x3f3f3f3f; typedef long long ll; struct inst { int num; int v; }; inst ax[100010]; int bn[100010]; int gg[200020]; int n; int cmp(inst a, inst b) { if (a.num == b.num) return a.v < b.v; else return a.num < b.num; } int change(int pos, int v) { for (int i = pos; i <= n; i += i&(-i)) { gg[i] += v; } return 0; } int qusum(int x) { int ans = 0; for (int i = x; i>0; i -= i&(-i)) { ans += gg[i]; } return ans; } int main(void) { int t; scanf("%d", &t); int zzz = 1; while (t--) { int ok = 1; scanf("%d", &n); memset(gg, 0, sizeof(gg)); for (int i = 1; i <= n; i++) { scanf("%d%d", &ax[i].num, &ax[i].v); } sort(ax + 1, ax + 1 + n, cmp); for (int i = 1; i <= n; i++) { int k = min(ax[i].v, n - i - ax[i].v); if (k < 0) { ok = 0; break; } int l = 1; int r = n; int mid; int aaa = 0;; k++; while (l <= r) { mid = (l + r) >> 1; if (mid - qusum(mid) >= k) { r = mid - 1; aaa = mid; } else l = mid + 1; } change(aaa, 1); bn[aaa] = ax[i].num; } printf("Case #%d:", zzz++); if (ok) { for (int i = 1; i <= n; i++) { printf(" %d", bn[i]); } printf("\n"); } else printf(" impossible\n"); } return 0; }