POJ 2828 Buy Tickets (线段树 or 树状数组+二分)
Posted Recoder
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了POJ 2828 Buy Tickets (线段树 or 树状数组+二分)相关的知识,希望对你有一定的参考价值。
题目链接:http://poj.org/problem?id=2828
题意就是给你n个人,然后每个人按顺序插队,问你最终的顺序是怎么样的。
反过来做就很容易了,从最后一个人开始推,最后一个人位置很容易就确定了,那最后第二个人的位置也可以推(与最后一个人的位置无关)...依次就都可以确定所有的人了。
用前缀和的思想,要是这个人的位置确定了,那么就标记这个人位置的值为0,然后回溯更新,跟求逆序对个数的思想比较类似。
线段树:
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 using namespace std; 5 const int MAXN = 2e5 + 5; 6 struct segtree { 7 int l , r , val; 8 }T[MAXN << 2]; 9 int x[MAXN] , y[MAXN] , ans[MAXN] , id; 10 11 void init(int p , int l , int r) { 12 T[p].l = l , T[p].r = r; 13 int mid = (l + r) >> 1; 14 if(l == r) { 15 T[p].val = 1; 16 return ; 17 } 18 init(p << 1 , l , mid); 19 init((p << 1)|1 , mid + 1 , r); 20 T[p].val = T[p << 1].val + T[(p << 1)|1].val; 21 } 22 23 void updata(int p , int num) { 24 int mid = (T[p].l + T[p].r) >> 1; 25 if(T[p].l == T[p].r) { 26 T[p].val = 0; 27 id = T[p].l; 28 return ; 29 } 30 if(num <= T[p << 1].val) { 31 updata(p << 1 , num); 32 } 33 else { 34 updata((p << 1)|1 , num - T[p << 1].val); 35 } 36 T[p].val = T[p << 1].val + T[(p << 1)|1].val; 37 } 38 39 int main() 40 { 41 int n; 42 while(~scanf("%d" , &n)) { 43 init(1 , 1 , n); 44 for(int i = 0 ; i < n ; i++) { 45 scanf("%d %d" , x + i , y + i); 46 x[i]++; 47 } 48 for(int i = n - 1 ; i >= 0 ; i--) { 49 updata(1 , x[i]); 50 ans[id] = y[i]; 51 } 52 for(int i = 1 ; i < n ; i++) { 53 printf("%d " , ans[i]); 54 } 55 printf("%d\n" , ans[n]); 56 } 57 }
树状数组+二分:
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 using namespace std; 5 const int MAXN = 2e5 + 5; 6 int bit[MAXN] , n , x[MAXN] , y[MAXN] , ans[MAXN]; 7 8 inline void add(int i , int num) { 9 for( ; i <= n ; i += (i & -i)) { 10 bit[i] += num; 11 } 12 } 13 14 int sum(int i) { 15 int s = 0; 16 for( ; i > 0 ; i -= (i & -i)) 17 s += bit[i]; 18 return s; 19 } 20 21 int main() 22 { 23 while(~scanf("%d" , &n)) { 24 memset(bit , 0 , sizeof(bit)); 25 for(int i = 1 ; i <= n ; i++) { 26 scanf("%d %d" , x + i , y + i); 27 x[i]++; 28 add(i , 1); 29 } 30 for(int i = n ; i >= 1 ; i--) { 31 int l = 1 , r = n , mid; 32 while(l < r) { 33 mid = (l + r) >> 1; 34 if(sum(mid) >= x[i]) 35 r = mid; 36 else 37 l = mid + 1; 38 } 39 ans[l] = y[i]; 40 add(l , -1); 41 } 42 for(int i = 1 ; i < n ; i++) { 43 printf("%d " , ans[i]); 44 } 45 printf("%d\n" , ans[n]); 46 } 47 }
以上是关于POJ 2828 Buy Tickets (线段树 or 树状数组+二分)的主要内容,如果未能解决你的问题,请参考以下文章
POJ - 2828 Buy Tickets(线段树单点更新)