Buy Tickets poj 2828

 

 

题意:一些人排队去买票。首先输入一个N,代表一共有N个人。接下来有N行输入,每行两个数。第I的两个数num和val,分别代表第I个人排在第num个人的后面,val代表第I个人的值。根据最后的排队情况依次输出每个人的值。

 

题解:线段树,倒叙插入。线段树的节点记录相应的区间有多少个空位。

首先按顺着看,某个人插入到哪个位置,目前他就在哪个位置,接着如果后面有人插到他前面,他就要先后移相应的位。

然后逆着看,最后一个人排在的位置一定是确定的,因为后面不会再有人再插到他前面。再往前某个人的位置这样确定:他插到的位置+后面插到他前面的人数。

因此在线段树更新时就可以这样:插入到它大于的第一个空位数的位置后(num指第num个人的后面,所以这个人的位置是num+1)。当某个人占了某个位子后,相应的线段树节点就标记为0表示这个位子被占了,其他的相应线段树节点都减一。

觉得自己讲的好乱啊,囧。。。总之在更新线段树时,被占的空位子就表示后面已经有人确定占到这个位子上了,在他前面排队的的人都要被在他后面排队的插到他前面的人往后挤一位。

 

详见代码吧:

View Code
 1 #include<cstdio>
 2 #include<cstring>
 3 #include<iostream>
 4 #include<algorithm>
 5 using namespace std;
 6 const int maxn=200005;
 7 struct node{
 8     int num,val;
 9 }data[maxn];
10 int sum[maxn<<2],ans[maxn];
11 void Build(int l,int r,int pos){
12     if(l==r){
13         sum[pos]=1;
14         return;
15     }
16     int mid=(l+r)>>1;
17     Build(l,mid,pos*2);
18     Build(mid+1,r,pos*2+1);
19     sum[pos]=sum[pos*2]+sum[pos*2+1];
20 }
21 void Updata(int p,int add,int l,int r,int pos){
22     if(l==r){
23         sum[pos]=0;
24         ans[l]=add;
25         return;
26     }
27     int mid=(l+r)>>1;
28     if(p<sum[pos*2])Updata(p,add,l,mid,pos*2);
29     else Updata(p-sum[pos*2],add,mid+1,r,pos*2+1);
30     sum[pos]=sum[pos*2]+sum[pos*2+1];
31 }
32 int main()
33 {
34      int n;
35      while(~scanf("%d",&n)){
36          Build(1,n,1);
37          for(int i=0;i<n;i++)
38              scanf("%d %d",&data[i].num,&data[i].val);
39          for(int i=n-1;i>=0;i--)
40              Updata(data[i].num,data[i].val,1,n,1);
41          for(int i=1;i<=n;i++)
42              printf("%d%c",ans[i],i==n?'\n':' ');
43      }
44      return 0;
45 }

 

 

 

 

 

 

posted on 2012-10-19 22:18  Acmer_Roney  阅读(174)  评论(0编辑  收藏  举报

导航