题目给出插队的过程,求最后队的序列。我当初想开一个大数组模拟,用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 }