ZOJ Monthly, August 2012 - C Cinema in Akiba 树状数组+二分


Cinema in Akiba
Time Limit: 3 Seconds      Memory Limit: 65536 KB

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 n integers a1, a2, ..., 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 m integers, q1, q2, ..., 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

题意:
3                输入n 表示n个人n个座位 第i个人的编号为i   
1 1 1          然后输入n个数表示从第一个没有坐人的地方起找到第几个空座坐下
3                然后输入m   表示m个询问
1 2 3          然后再输入m个人的编号 询问这几个人在第几个座位上

思路 首先要找到第i个空位置 如果一个一个的标记着去查找第i个空位在那 这样肯定是超时的
那怎么办  用树状数组 线段树也可以  (假如用1标记空位置 0标记 已经有人)第i个即前面的和相加为i 所以要利用树状数组中的求sum
如果直接暴力求sum铁定超时
用树状数组去求sum要快好多 然后用二分法精确的找到和为i的sum

我下面的程序 让所有的值初始化为-1 如果有人做了就加1 变成0    那么第i个空位置就是取绝对值后的sum值等于i时对应的位置

本题 给我一个大的反思 就是: 有些题看起来很复杂 但是要敢于去写  有了想法 不要畏惧拍不出来 而放弃


#include<stdio.h>
#include<map>
#include<string.h>
#include<math.h>
using namespace std;
int a[50100],n,used[50100];//记住 a[i]里面存的是一段的和 而不是某一个点的和 从1到i一段的和
int lowbit(int x)
{
    return x&(-x);
}
void add(int i,int val)
{
    while(i<=n)
    {
        a[i]+=val;
        i+=lowbit(i);
    }
}
int sum(int i)
{
    int s=0;
    while(i>0)
    {
        s+=a[i];
        i-=lowbit(i);
    }
    return s;
}
int binsearch(int num)
{
	int start=1,end=n,i,mid;
	while(start<=end)
	{
		mid=(end+start)/2;
		i=-(sum(mid));
		if(num==i) {return mid; }
		if(num<=i) end=mid;
		if(num>i) start=mid+1;
	}
}
int main()
{
    int m,i,num,k;
	map<int,int>mp;
	while(scanf("%d",&n)!=EOF)
	{
		mp.clear();
		memset(a,0,sizeof(a));
		memset(used,0,sizeof(used));
		for(i=1;i<=n;i++)
			add(i,-1);
		for(k=1;k<=n;k++)
		{
			scanf("%d",&num);
			i=binsearch(num);
			while(used[i]) i--;
			used[i]=1;
			add(i,1);
			mp[k]=i;
		}
		
		scanf("%d",&m);
		for(i=1;i<m;i++)
		{
			scanf("%d",&num);
			printf("%d ",mp[num]);
		}
		scanf("%d",&num);
		printf("%d\n",mp[num]);
		
	}
	return 0;
}




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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值