1. 程式人生 > >HDU - 5493 Queue(二分+樹狀陣列)

HDU - 5493 Queue(二分+樹狀陣列)

題目連結:傳送門

 

題意:給你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;
}