題目鏈接:http://poj.org/problem?id=2828

/**//*
題意:
給定N(1 <= N <= 200000)個整數對(A,B),表示在A右邊的位置插入一個B,
經過N次操作后問最后的B序列的排列情況。
題解:
樹狀數組 或者 線段樹

思路:
這題的數據量比較大,一開始可以模擬一下過程,但是直接暴力肯定是超時
的,因為每次插入過程,這個位置的后面的元素必然是要順序往后移動的。所以
總的復雜度高達O(n^2)。
但是這個問題可以轉化,我們這樣考慮,對于任意兩個整數對(A1,B1)和(A2,B2)
保證(A1,B1)在(A2,B2)之前出現,如果A1小于A2,后面的整數對是不影響前面整
數對的位置關系的,否則B1的位置必然要受到B2的影響而向后移動一位。
于是A1和A2之間就存在一個逆序關系,我們可以聯想到樹狀數組求逆序數時
候的做法,從后往前,對于最后一個數,它的位置就是An,因為之后沒有插入數
了,它已經穩定下來了,然后將這個位置插入到樹狀數組的相應位置去,每次掃
描到當前數的時候二分枚舉當前數前面有多少“空位”,空位的統計可以采用樹
狀數組的成段求和,找到后將這個數插入,N次操作后答案就保存下來了。
*/

#include <iostream>

using namespace std;

#define maxn 200010

int n;
int c[maxn];


struct point
{
int A, B;
}pt[maxn];


int lowbit(int x)
{
return x & (-x);
}


void add(int pos)
{

while(pos <= n)
{
c[pos] ++;
pos += lowbit(pos);
}
}


int sum(int pos)
{
int s = 0;

while(pos > 0)
{
s += c[pos];
pos -= lowbit(pos);
}
return s;
}

int ans[maxn];


int main()
{
int i;

while(scanf("%d", &n) != EOF)
{
for(i = 1; i <= n; i++)
c[i] = 0;

for(i = 1; i <= n; i++)
{
scanf("%d %d", &pt[i].A, &pt[i].B);
pt[i].A ++;
}

for(i = n; i >= 1; i--)
{
int l = 1;
int r = n;
int as = 1;

while(l <= r)
{
int m = (l + r) >> 1;

if(m - sum(m) >= pt[i].A)
{
r = m - 1;
as = m;
}else
l = m + 1;
}
ans[as] = pt[i].B;
add(as);
}

for(i = 1; i <= n; i++)
{
if(i != 1)
printf(" ");
printf("%d", ans[i]);
}
puts("");
}
return 0;
}