poj 2828 Buy Tickets

题目给出插队的过程,求最后队的序列。我当初想开一个大数组模拟,用1表示有人,0表示没人,从后往前推,每确定一个人,就把他所在位置的1改为0,剩下的人再根据0,1算序号。这个想法我放弃了,因为复杂度是O(n)的。后来我才恍然大悟,线段树不就是把对区间的操作从O(n)化为O(logn)的么?这样问题就解决了。

 1 #include <stdio.h>
 2 #include <string.h>
 3 const int N = 200010;
 4 int p[N],w[N],order[N];
 5 int tree[N<<2],D;
 6 void update(int n)
 7 {
 8     while(n)
 9     {
10         tree[n>>1] = tree[n] + tree[n^1];
11         n >>= 1;
12     }
13 }
14 void push(int i)
15 {
16     int m,n = p[i]+1;
17     for(m = 1; m < D;)
18     {
19         if(tree[m<<1] >= n) m <<= 1;
20         else n -= tree[m<<1], m = m<<1|1;
21     }
22     tree[m] = 0;
23     update(m);
24     order[m-D] = w[i];
25 }
26 int main()
27 {
28     int n,i;
29     while(~scanf("%d",&n))
30     {
31         for(D = 1; D < n; D <<= 1);
32         memset(tree,0,sizeof tree);
33         for(i = 0; i < n; i++)
34             scanf("%d%d",&p[i],&w[i]), tree[D+i] = 1;
35         for(i = D-1; i; i--)
36             tree[i] = tree[i<<1] + tree[i<<1|1];
37         for(i = n-1; i >= 0; i--)
38             push(i);
39         printf("%d",order[0]);
40         for(i = 1; i < n; i++)
41             printf(" %d",order[i]);
42         printf("\n");
43     }
44     return 0;
45 }
原文地址:https://www.cnblogs.com/lzxskjo/p/2661116.html