题目真不难。。。
按高度从小到大加到线段树统计下次数求第k大就可以了,由于要字典序最小,所以每次把当前的尽量往前加,有k个人比它高,就两个位置,k+1和n-k,贪心取最靠前的就行了。
水题!
#include<iostream> #include<cstdio> #include<cstring> #include<cstdlib> #include<algorithm> #define REP(i,a,b) for(int i=a;i<=b;i++) #define MS0(a) memset(a,0,sizeof(a)) #define key_val ch[ch[rt[i]][1]][0] #define lson l,m,rt<<1 #define rson m+1,r,rt<<1|1 using namespace std; typedef long long ll; const int maxn=1000100; const int INF=1e9+10; int n; struct Node { int h,k; friend bool operator<(Node A,Node B) { return A.h<B.h; } };Node a[maxn]; int ans[maxn]; int cnt[maxn<<2]; void push_up(int rt) { cnt[rt]=cnt[rt<<1]+cnt[rt<<1|1]; } void build(int l,int r,int rt) { if(l==r){ cnt[rt]=1; return; } int m=(l+r)>>1; build(lson); build(rson); push_up(rt); } int find_kth(int k,int l,int r,int rt) { if(l==r){ cnt[rt]=0; return l; } int m=(l+r)>>1; int res=0; if(k<=cnt[rt<<1]) res=find_kth(k,lson); else res=find_kth(k-cnt[rt<<1],rson); push_up(rt); return res; } int main() { #ifndef ONLINE_JUDGE freopen("in.txt","r",stdin); #endif int T;cin>>T; REP(casen,1,T){ scanf("%d",&n); REP(i,1,n) scanf("%d%d",&a[i].h,&a[i].k); sort(a+1,a+n+1); build(1,n,1); bool flag=1; int rk,pos; REP(i,1,n){ if(a[i].k+1>cnt[1]){ flag=0;break; } rk=min(a[i].k+1,cnt[1]-a[i].k); pos=find_kth(rk,1,n,1); ans[pos]=a[i].h; } printf("Case #%d:",casen); if(!flag) puts(" impossible"); else{ REP(i,1,n) printf(" %d",ans[i]); puts(""); } } return 0; }