题意:给n个人的身高和一个k,k代表的是这个人前边比他高的人的数量或者是后面的比他高的人的数量,问能否将这n个人满足条件的排序,有多解时输出字典序最小的
思路:看到100000个人,感觉是线段树,但是没什么思路,看了大神们的博客,发现只要转化一下便是简单的线段树模型了,对于每个人来说,k就是前边留k个位置,后者后边留k个位置,当然这两个我肯定要选的是小的那个位置,这要是为了满足字典序最小,而这样做的前提是先将n个人按高度排序,为什么这么排,我们可以这样想,对于高的人来说,矮个的人对他的位置肯定是没有影响的,因为他的k是比他高的人产生的,这样我们可以维护一个线段树,如现在高度的人要在第pos的位置,那么我们找到线段树中的第pos个不为0的位置更新就好了,刚刚写的二分+线段树找位置写的超时了,换成树状数组应该可以过,没尝试,也可以直接更新的时候就找到位置,这样更简单一些
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int inf=0x3f3f3f3f;
const int INF=0x3f3f3f3f3f3f3f3f;
const int maxn=100010;
int num[maxn*4],ans[maxn];
struct edge{
int height,k;
}es[maxn];
bool cmp(const edge &a,const edge &b){
return a.height<b.height;
}
void buildtree(int le,int ri,int node){
if(le==ri){
num[node]=1;
return ;
}
int t=(le+ri)>>1;
buildtree(le,t,node<<1);
buildtree(t+1,ri,node<<1|1);
num[node]=num[node<<1]+num[node<<1|1];
}
void update(int pos,int k,int le,int ri,int node){
if(le==ri){
num[node]=0;
ans[le]=es[k].height;
return ;
}
int t=(le+ri)>>1;
if(pos<=num[node<<1]) update(pos,k,le,t,node<<1);
else update(pos-num[node<<1],k,t+1,ri,node<<1|1);
num[node]=num[node<<1]+num[node<<1|1];
}
int main(){
int T,cas=1,n;
scanf("%d",&T);
while(T--){
scanf("%d",&n);
for(int i=1;i<=n;i++) scanf("%d%d",&es[i].height,&es[i].k);
sort(es+1,es+1+n,cmp);
int flag=0,sum=n;
buildtree(1,n,1);
for(int i=1;i<=n;i++){
if(sum-es[i].k<=0){
flag=1;break;
}
int pos1=sum-es[i].k;
int pos2=++es[i].k;sum--;
int id=min(pos1,pos2);
update(id,i,1,n,1);
}
printf("Case #%d: ",cas++);
if(flag) printf("impossible\n");
else{
for(int i=1;i<=n;i++){
if(i!=n) printf("%d ",ans[i]);
else printf("%d\n",ans[i]);
}
}
}
return 0;
}