题目有难度,线段树。
大致题意:按顺序给定n个人插队时其前方人的个数,并同时给定每个人的ID,令队首元素是第一个人,其前方人个数为0,现在要求按排队的顺序依次输入最终队列的人的编号。
题意很明确。
分析如下:
可令线段树节点结构如下:
struct Node{
int l,r,value,pos;
}node[Max*3];
其中value为该区间范围内还空余的位置个数,而pos为单位区间的坐标,则有如下式子成立:令输入为d,v
1)若d+1大于node[Lson(po)].value,则应该插入右节点,且权值减少node[Lson(po)].value
2)若d+1小于或等于node[Lson(po)].value,则因该插入左节点
下面是代码:10724K+1500MS
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define Max 200010
#define Lson(p) (p<<1)
#define Rson(p) (p<<1|1)
#define Mid(a,b) ((a+b)>>1)
struct Node{
int l,r,value,pos;
}node[Max*3];
int Input[Max][2];
int ans[Max];
int n;
void build_tree(int left,int right,int po){ //创建线段树,注意value为给区间还空余的位置,初始时即为区间长度
node[po].l=left,node[po].r=right,node[po].value=right-left+1;
if(left==right){
node[po].pos=left;
return ;
}
int mid=Mid(left,right);
build_tree(left,mid,Lson(po));
build_tree(mid+1,right,Rson(po));
}
void update_tree(int d,int v,int po){ //更新线段树,同时确定最终队列位置
node[po].value--;
if(node[po].l==node[po].r){ // 若找到最终队列位置
ans[node[po].pos]=v; // 赋值编号
return ;
}
if(d>node[Lson(po)].value) //若大于还剩余的空位置,则在右儿子
update_tree(d-node[Lson(po)].value,v,Rson(po));
else //否则在左儿子
update_tree(d,v,Lson(po));
}
int main(){
while(scanf("%d",&n)!=EOF){
build_tree(1,n,1); //建树,区间为1——n
for(int i=1;i<=n;i++){ //输入n个人插队信息和个人ID
scanf("%d%d",&Input[i][0],&Input[i][1]);
Input[i][0]++; //增加1
}
for(int i=n;i>=1;i--) //逆序更新线段树
update_tree(Input[i][0],Input[i][1],1);
for(int i=1;i<=n;i++) //按1——n位置输出ID
printf("%d ",ans[i]);
printf("\n");
}
return 0;
}