題意:買火車票時總有人插隊,每人有兩個屬性,插入位置pos[i] (pos[i]代表此人前面的總人數),以及人物編號 value[i]。在每一輪輸入後,按隊伍順序輸出人物的編號。
題解:處理點的線段樹。從後往前推,則可以避免後來人對pos的影響,這樣一來每個人的pos都是精確的。
#include <iostream>using namespace std;#define MAX 200005int 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;}