ZOJ3635——Cinema in Akiba(树状数组+二分)

Description

Cinema in Akiba (CIA) is a small but very popular cinema in Akihabara. Every night the cinema is full of people. The layout of CIA is very interesting, as there is only one row so that every audience can enjoy the wonderful movies without any annoyance by other audiences sitting in front of him/her.

The ticket for CIA is strange, too. There are n seats in CIA and they are numbered from 1 to n in order. Apparently, n tickets will be sold everyday. When buying a ticket, if there are k tickets left, your ticket number will be an integer i (1 ≤ i ≤ k), and you should choose the ith empty seat (not occupied by others) and sit down for the film.

On November, 11th, n geeks go to CIA to celebrate their anual festival. The ticket number of the ith geek is ai. Can you help them find out their seat numbers?

Input

The input contains multiple test cases. Process to end of file.
The first line of each case is an integer n (1 ≤ n ≤ 50000), the number of geeks as well as the number of seats in CIA. Then follows a line containing nintegers a1a2, ..., an (1 ≤ ai ≤ n - i + 1), as described above. The third line is an integer m (1 ≤ m ≤ 3000), the number of queries, and the next line is mintegers, q1q2, ..., qm (1 ≤ qi ≤ n), each represents the geek's number and you should help him find his seat.

Output

For each test case, print m integers in a line, seperated by one space. The ith integer is the seat number of the qith geek.

Sample Input
3
1 1 1
3
1 2 3
5
2 3 3 2 1
5
2 3 4 5 1
Sample Output
1 2 3
4 5 3 1 2

题意:

有一些人来电影院,他们按照顺序买票,每张票上有一个数字ai,代表他应当坐到第ai个空位上。

现在给出一定的询问。对于每个询问qi,输出第qi个买票人坐的位置。

分析:

假设现在前面已经有一些人买票入座了,那么后面的人买票之后要找到他所对应的位置比较好的办法就是二分查找。

但是二分查找的前提是序列单调,而且数组同时又是动态更新的,所以很自然的想到了树状数组。

树状数组可以求出某个位置之前共有多少空位。然后二分就可以找到目标位置。开一个数组记录每个人的位置。并且入座后跟新树状数组即可。

#include <algorithm>
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <cstring>
#include <iostream>
#define INF 0x7fffffff
using namespace std;

typedef long long LL;
const int N = 5e4 + 10;

int a[N],q[N],c[N],n;

int lowbit(int x)
{
    return x&-x;
}
void update(int x,int v)
{
    for(int i=x;i<=n;i+=lowbit(i))
        a[i]+=v;
    return;
}
int getsum(int x)
{
    int sum=0;
    for(int i=x;i>0;i-=lowbit(i))
        sum+=a[i];
    return sum;
}
int main()
{
    int m;
    while(scanf("%d",&n)!=EOF)
    {
        memset(a,0,sizeof(a));
        memset(q,0,sizeof(q));
        for(int i=1;i<=n;i++)
        {
            int x;
            scanf("%d",&x);
            int l=1,r=n,mid;
            while(l<r)
            {
                mid=(l+r+1)/2;
                int t=mid-getsum(mid-1);
                if(t>x)
                    r=mid-1;
                else if(t<=x) l=mid;
            }
            q[i]=l;
            update(l,1);
        }
        scanf("%d",&m);
        for(int i=0;i<m;i++)
        {
            int x;
            scanf("%d",&x);
            if(i==m-1) printf("%d\n",q[x]);
            else printf("%d ",q[x]);
        }
    }

    return 0;
}



  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值