http://poj.org/problem?id=2828
后序遍历,假设 x 号人插入到队伍中的某一个位子,那么他的位子是安全的,因为他后没有其他人,也就不会挤掉他的位子,所以,我们可以先接受完所有的数据,然后按照后序遍历就相当于,拿人来找空位,
0 77
1 51
1 33
2 69 就相当于, 69号人来了,找地3个空位子,然后他站到那里, 33 来了,找一个空位子,站在那里。。。。。。。当所有的人都找到位子之后,整个序列就完整了。
#include<cstdio>
#include<vector>
#include<iostream>
#include<cstring>
using namespace std;
int sum[800010],value[800010],pos[800010],num[800010];
void build(int l,int r,int root)
{
sum[root] = (r - l) +1;//整个区间的空位子的个数,等于区间的长度
if(l == r) return ;
int mid = (l + r) /2;
build(l,mid,2*root);
build(mid+1,r,2*root+1);
}
int update(int x,int l ,int r,int root)
{
int mid = (l + r)/2;
sum[root] -= 1;//该区间内会有一个人找到位子,所以,sum 值 减去1
if(l == r) return l; //如果找到了位子,返回位子的编号
if(sum[2*root] >= x)// 如果左孩子的空位子个数满足我们要找的空位子编号,在做孩子找
update(x,l,mid,2*root);
else
{
x -= sum[2*root];
/*如果左孩子的空位子不够,就在右孩子找,
这时候相当于前面已经有了左孩子的空位子的个数,
要找的位子的编号应该减掉左孩子空位子的个数*/
update(x,mid+1,r,2*root+1);
}
}
int main()
{
int n,i,a,b;
while(cin>>n)
{
memset(value,0,sizeof(value));
memset(pos,0,sizeof(pos));
memset(num,0,sizeof(num));
for(i = 1; i <= n; i++)//注意把 pos 的各个值都加上1
scanf("%d%d",&pos[i],&value[i]),pos[i]++;
build(1,n,1);
for(i = n; i > 0; i--)
{
int id = update(pos[i],1,n,1); //找到位子,然后把该位子的人的值记录下来
num[id] = value[i];
}
cout<<num[1];
for(i = 2; i <= n; i++)
printf(" %d",num[i]);//cout<<" "<<num[i];
cout<<endl;
}
return 0;
}