按身高排序,每个人前面最高的人数有上限,如果超出上限说明impossible,
每次考虑最小的人,把他放在在当前的从左往右第k+1个空位
因为要求字典序最小,所以每次k和(上限-k)取min值。
没有修改操作,只有删除,可用线段树维护空位数量s,每次类似名次树判断一下第k个空位在哪颗子树上(原来这叫划分树
到达叶子返回位置编号并减少空位数量,push_up的时候维护一下空位数量。
#include<bits/stdc++.h> using namespace std; const int maxn = 1e5+5; struct Nd { int h,k; void IN(){ scanf("%d%d",&h,&k); } bool operator < (const Nd& rh) const{ return h < rh.h; } }nd[maxn]; int N; bool chk() { sort(nd,nd+N); for(int i = 0,n = N-1; i <= n; i++){ if(nd[i].k > n-i) return false; nd[i].k = min(nd[i].k,n-i-nd[i].k); } return true; } #define lo (o<<1) #define ro (o<<1|1) #define lsn L, M, lo #define rsn M+1,R, ro #define mid int M = (L+R)>>1; #define para int L = 0, int R = N-1,int o = 1 int s[maxn<<2]; void build(para) { s[o] = R-L+1; if(L==R) return; mid build(lsn); build(rsn); } int qk; int qud(para) { if(L==R){ s[o]--; return L; } mid int re = 0; if(s[lo]>=qk) re = qud(lsn); else { qk -= s[lo];re = qud(rsn); } s[o] = s[lo] + s[ro]; return re; } int ans[maxn]; //#define LOCAL int main() { #ifdef LOCAL freopen("in.txt","r",stdin); #endif int T, ks = 0; scanf("%d",&T); while(T--){ scanf("%d",&N); for(int i = 0; i < N; i++) nd[i].IN(); printf("Case #%d:",++ks); if(!chk()) { puts(" impossible"); continue; } build(); for(int i = 0; i < N; i++){ qk = nd[i].k+1; ans[qud()] = nd[i].h; } for(int i = 0; i < N; i++){ printf(" %d",ans[i]); } puts(""); } return 0; }