题意:买火车票时总有人插队,每人有两个属性,插入位置pos[i] (pos[i]代表此人前面的总人数),以及人物编号 value[i]。在每一轮输入后,按队伍顺序输出人物的编号。
题解:处理点的线段树。从后往前推,则可以避免后来人对pos的影响,这样一来每个人的pos都是精确的。
#include <iostream>
using namespace std;
#define MAX 200005
int pos[MAX], value[MAX], out[MAX];
struct item
{
int left, right, person;/*person代表当前节点区间可容纳的人数*/
} node[MAX*3];
void build_tree ( int l, int r, int root )
{
node[root].left = l;
node[root].right = r;
node[root].person = r - l + 1;
if ( l == r ) return;
int mid = ( l + r ) / 2;
build_tree ( l, mid, root * 2 );
build_tree ( mid + 1, r, root * 2 + 1 );
}
int update ( int p, int root )
{
node[root].person --; /*每插入一个人,则节点区间的容量减小1*/
if ( node[root].left == node[root].right ) /*当左右坐标相等时,已经确定到点,即插入者得位置确定*/
return node[root].left;
int lchild = root * 2;
int rchild = root * 2 + 1;
if ( node[lchild].person >= p ) /*r若左子树的容量大于插入者的位置,那么插入者的最终位置一定在左子树的区间内*/
return update( p, lchild );
else
{
p -= node[lchild].person; /* 假设某人的需要给前面的人留5个空位,左子树可以提供3个,那么就还需右子树提供2个*/
return update ( p, rchild );
}
}
int main()
{
int n, index, i;
while ( scanf("%d",&n) != EOF )
{
build_tree( 1, n, 1 );
for ( i = 1; i <= n; ++i )
scanf("%d%d", &pos[i], &value[i]);
for ( i = n; i >= 1; --i )
{
index = update ( pos[i]+1, 1 );
out[index] = value[i];
}
for ( i = 1; i <= n; ++i )
printf("%d ",out[i]);
putchar('\n');
}
return 0;
}