來源:http://poj.org/problem?id=2828
題意:有一些人在排隊買票,但是有些人會插隊。現在給出這些插隊的信息,問最後人的順序。
思路:一道線段樹的好題。我們從前向後考慮的話,當第i個人插隊的時候,他插隊到第posi個人的後面,也就是說,此時,他前面已經有了posi個人。因此,我們可以從後向前考慮,這樣,第i個人插隊到第posi個人的後面,說明了他的前方還有posi個空位置。因此,就可以用線段樹了,線段樹的結點保存的是該區間有多少個空位置。
ac代碼:
#include <iostream>
#include <cstdio>
#include <string.h>
using namespace std;
const int N = 200020;
int id;
struct people
{
int pos,val;
}pp[N];
struct tree
{
int lp,rp,cnt;
int getmid()
{
return (lp + rp) / 2;
}
}tt[N * 4];
void built_tree(int lp,int rp,int pos)
{
tt[pos].lp = lp;
tt[pos].rp = rp;
tt[pos].cnt = 0;
if(lp == rp)
{
tt[pos].cnt = 1;
return;
}
int mid = tt[pos].getmid();
built_tree(lp,mid,pos*2);
built_tree(mid+1,rp,pos*2+1);
tt[pos].cnt = tt[pos*2].cnt + tt[pos*2+1].cnt;
}
void update(int num,int pos)
{
if(tt[pos].lp == tt[pos].rp)
{
tt[pos].cnt = 0;
id = tt[pos].lp;
return;
}
if(num <= tt[pos*2].cnt)
{
update(num,pos*2);
}
else
{
update(num - tt[pos*2].cnt,pos*2+1);
}
tt[pos].cnt = tt[pos*2].cnt + tt[pos*2+1].cnt;
}
int main()
{
//freopen("1.txt","r",stdin);
int n;
while(scanf("%d",&n) != EOF)
{
built_tree(1,n,1);
for(int i = 0; i < n; ++i)
{
scanf("%d%d",&pp[i].pos,&pp[i].val);
}
int ans[N];
for(int i = n-1; i >= 0; --i)
{
update(pp[i].pos + 1,1);
ans[id] = pp[i].val;
}
for(int i = 1; i < n; ++i)
{
printf("%d ",ans[i]);
}
printf("%d\n",ans[n]);
}
return 0;
}