题目:
以时间顺序给定每个人插队的位置自己的序号,要求输出队伍最后的序列。
思路:
刚开始做直接就用vector莽,笑死,根本过不了。 直接暴力是肯定过不了这一题的,O( n ^ 2 ) 的复杂度肯定没法过2e5。。。所以我们需要对他进行一个优化,具体怎么优化呢。首先我们如果正向思考,每次插入都要将插入者后面或者前面的人全部后移一格,时间复杂度无法支持。那么我们可以考虑逆向思维,倒着插入,这样子每次只需要考虑该位置前面有多少个空格即可。用线段树进行优化就可以达到O( nlogn ) 的复杂度。
代码:
#include <cstdio>
#include <iostream>
#define MaxN 2000001
using namespace std;
int linel[ 2 ][ MaxN ];
int ans[ MaxN ];
typedef struct {
int left, right, sum;
} node;
node tree[ MaxN << 2 ];
void build( int po, int left, int right ) {
tree[ po ].left = left;
tree[ po ].right = right;
if ( left == right ) {
tree[ po ].sum = 1;
return;
}
int middle = ( left + right ) / 2;
build( po * 2, left, middle );
build( po * 2 + 1, middle + 1, right );
tree[ po ].sum = tree[ po * 2 ].sum + tree[ po * 2 + 1 ].sum;
}
void update( int po, int need, int number ) {
if ( tree[ po ].left == tree[ po ].right ) {
ans[ tree[ po ].left ] = number;
tree[ po ].sum = 0;
return;
}
if ( need <= tree[ po * 2 ].sum ) {
update( po * 2, need, number );
} else {
update( po * 2 + 1, need - tree[ po * 2 ].sum, number );
}
tree[ po ].sum = tree[ po * 2 ].sum + tree[ po * 2 + 1 ].sum;
}
int main( ) {
int i, j, k;
int N, M;
while ( scanf("%d", &N ) != EOF ) {
for ( i = 1; i <= N; i ++ ) {
scanf("%d %d", &linel[ 0 ][ i ], &linel[ 1 ][ i ] );
}
build( 1, 1, N );
for ( i = N; i > 0; i -- ) {
update( 1, linel[ 0 ][ i ] + 1, linel[ 1 ][ i ] );
}
for ( i = 1; i <= N; i ++ ) {
printf("%d ", ans[ i ] );
}
putchar( '\n' );
}
return 0;
}