這題也是用線段樹來解,慚愧的說沒在網上找過資料前真沒想到這是用線段樹做的
剛開始以爲是直接把值往裏添然後統計之前已經添過的人的數量,當然這個顯然是錯誤的。
後來也是在看了別人的文章之後有了想法。
1、最後來插隊的那個人直接能確定他的最終位置
2、從最後的人開始枚舉,反過來去考慮整個插隊的過程,如果一個人要插在第i個人的後面,那麼也就說在他之前應當i個人,而當前已經插入到樹中的人其實是在他之後纔來的,所以,反過來一想,此時,必須在這個人前面留下i個位置,這i個位置是留給比他先來的人插的
按照這樣的過程就能得到最後的隊列了
代碼中
node中的count表示在該節點下共有多少個空位置沒被插隊
update就是插隊的過程(從最後那個人開始)
如果一個節點的左節點的count>i (i是他要插入的位置,如0的時候必須是留一個空位,這個空位就是把他自己插入的,1的時候留兩個,以此類推),往左節點遞歸,知道最後l==r,否則,就得往右節點插入,而往右節點插入的時候必須算上左節點的空位數,所以得 i-左節點的空位數
(在代碼裏p就表示這裏的i)
輸出結果的話其實就是找到線段樹的所有葉子,從左往右輸出即可
#include <cstdio>
#include <cstring>
#define FF(i,n) for(int i=0; i<n; i++)
const int MAX = 200010;
struct node
{
int count,val;
}tree[MAX<<2];
void push_up(int rt)
{
tree[rt].count = tree[rt<<1].count + tree[(rt<<1)+1].count;
}
void build(int l,int r,int rt)
{
if(l==r)
{
tree[rt].count = 1;
tree[rt].val = -1;
return;
}
int mid = (r+l)>>1;
build(l,mid,rt<<1);
build(mid+1,r,(rt<<1)+1);
push_up(rt);
}
void update(int p,int val,int l,int r,int rt)
{
if(l==r)
{
tree[rt].count = 0;
tree[rt].val = val;
return;
}
int mid = (r+l)>>1;
if(tree[rt<<1].count>p)
update(p,val,l,mid,rt<<1);
else update(p-tree[rt<<1].count,val,mid+1,r,(rt<<1)+1);
push_up(rt);
}
int cnt;
void print(int l,int r,int rt)
{
if(l==r)
{
if(cnt) printf(" ");
printf("%d",tree[rt].val);
cnt++;
return;
}
int mid = (r+l)>>1;
print(l,mid,rt<<1);
print(mid+1,r,(rt<<1)+1);
}
int x[MAX],y[MAX];
int main()
{
int n;
while(scanf("%d",&n)==1)
{
build(1,n,1);
FF(i,n)
scanf("%d%d",&x[i],&y[i]);
FF(i,n)
update(x[n-1-i],y[n-1-i],1,n,1);
cnt=0;
print(1,n,1);
puts("");
}
return 0;
}