Zoj 3635 <树状数组+二分>

题意:

给出n表示geeks人数..也是位置总数..

给出a1 a2 .. ai .. an 表示第 i 个人想要坐从左往右第 ai 个空位..

给出m表示询问的个数..

给出m个数b1 b2 .. bi .. bn 表示询问第 bi 个人的位置..

思路:

如果模拟过程..

应该是先按要求排好位置..然后输出位置值..

排好位置的过程就用到了二分..

用树状数组表示当前位置前有多少个空位..

然后二分找出满足当前位置前面空位有 ai 个的位置..

Tips:

记得安排好第i个geeks的位置后要modify树状数组..

Code:

View Code
 1 #include <stdio.h>
 2 #include <cstring>
 3 #include <algorithm>
 4 using namespace std;
 5 #define clr(x) memset(x, 0, sizeof(x))
 6 
 7 int n;       
 8 int c[100001]; 
 9 int lowbit(int x)
10 {
11    return (x)&(-x);
12 }
13 void modify(int pos,int x)
14 {
15     while(pos<=n)
16     {
17         c[pos]+=x;
18         pos+=lowbit(pos);
19     }
20 }
21 int getSum(int x)
22 {
23       int sum=0;
24       while(x>0)
25       {
26          sum+=c[x];
27          x-=lowbit(x);
28       }
29       return sum;
30 }
31 
32 int ans[50010];
33 int arr[50010];
34 int main()
35 {
36     int i, j, k;
37     int m, tmp;
38     while(scanf("%d", &n) != EOF)
39     {
40         clr(c);
41         clr(ans);
42         clr(arr);
43         for(i = 1; i <= n; ++i)
44         modify(i, 1);
45 
46         for(i = 1; i <= n; ++i){
47             scanf("%d", &tmp);
48             int r = n, l = 1, mid;
49             while(r > l)
50             {
51                 mid = (r+l)/2;
52                 if(getSum(mid) >= tmp) r = mid;
53                 else l = mid+1;
54             }
55             
56             arr[i] = r;
57             modify(r, -1);
58         }
59 
60 
61         scanf("%d", &m);
62         for(i = 0; i < m; ++i){
63             scanf("%d", &tmp);
64             ans[i] = arr[tmp];
65         }
66 
67         for(i = 0; i < m; ++i)
68         printf("%d%c", ans[i], i == m-1?'\n':' ');
69     }
70 
71     return 0;
72 }

 

原文地址:https://www.cnblogs.com/Griselda/p/2657728.html