题目:http://acm.hdu.edu.cn/showproblem.php?pid=5493
题意:给你n个人的身高和他前面或后面比他高的人数,求一个满足条件的最小字典序的排列方式
要满足最小字典序,所以我们从小到大放置,并尽量往前放
放当前的人时,后放的一定比他高,所以他前面必须要留一些位置来满足条件
那么我们可以用线段树来维护空余的位置
因为可能往前或往后看,那我们就贪心的选取前面比他大的人少的数据
之后只需要线段树单点更新就行了
#include<iostream> #include<cstdio> #include<cstring> #include<string> #include<cmath> #include<algorithm> #include<vector> #include<queue> #include<stack> #include<map> #include<set> #define lson i<<1 #define rson i<<1|1 using namespace std; const int N=1e5+5; pair<int,int> a[N]; int ans[N],sum[N<<2]; void build(int i,int l,int r) { sum[i]=1; if (l==r) return; int mid=(l+r)>>1; build(lson,l,mid); build(rson,mid+1,r); sum[i]=sum[lson]+sum[rson]; } void update(int i,int l,int r,int k,int val) { if (l==r) { ans[l]=val; sum[i]=0; return; } int mid=(l+r)>>1; if (sum[lson]>=k) update(lson,l,mid,k,val); else update(rson,mid+1,r,k-sum[lson],val); sum[i]=sum[lson]+sum[rson]; } int main() { int T; scanf("%d",&T); for(int ca=1;ca<=T;ca++) { int n; scanf("%d",&n); for(int i=1;i<=n;i++) scanf("%d%d",&a[i].first,&a[i].second); sort(a+1,a+1+n); build(1,1,n); int flag=1; for(int i=1;i<=n;i++) { int t=min(a[i].second,n-i-a[i].second); if (t<0) { flag=0; break; } update(1,1,n,t+1,a[i].first); } printf("Case #%d: ",ca); if (flag==0) printf("impossible "); else { for(int i=1;i<n;i++) printf("%d ",ans[i]); printf("%d ",ans[n]); } } return 0; }