http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=3635
题意:有n个geek,每个人一张票,每个票号ai表示这个geek要坐在当前第ai个空座上,入座顺序亦为1到n。下面输入query,分别要求输出输入的那个编号的geek座位号。
题解:树状数组。开始时每个点均为1插入,表示每个座位都是空座。然后对于要求为ai的空座,二分查找满足sum(ans)==ai&&sum(ans-1)==ai-1即为答案。保存后查询时输出,同时删去ans上点。
#include <cstdio>
#include <cstring>
#include <cmath>
#include <map>
#include <set>
#include <vector>
#include <iostream>
#include <algorithm>
#include<string>
using namespace std;
//const double eps=1e-7;
//const double INF=1e50;
//const double pi=acos(-1);
#define N 50005
#define M 10000
int c[N],n,ans[N];
void add(int p,int d)//p位置上加d
{
while(p<=n)
{
c[p]+=d;
p+=p&(-p);//lowbit[i]=i&(-i);
}
}
int sum(int p)//a[1]+...+a[p]
{
int ret=0;
while (p)
{
ret+=c[p];
p-=p&(-p);
}
return ret;
}
int find_kth(int k)//log(n)复杂度
{
int s=1,t=n,mid,s1,s2;
while (s<=t)
{
mid=(s+t)/2;
s1=sum(mid);
s2=sum(mid-1);
if (s1==k && s2==(k-1)) return mid;
else if (s1<k) s=mid+1;
else t=mid-1;
}
return mid;
}
int main()
{
//freopen("a","r",stdin);
int i,ai,an,m;
while (scanf("%d",&n)!=EOF)
{
for (i=1;i<=n;i++) add(i,1);
for (i=1;i<=n;i++)
{
scanf("%d",&ai);
an=find_kth(ai);
ans[i]=an;
add(an,-1);
}
scanf("%d",&m);
for (i=1;i<=m;i++)
{
scanf("%d",&an);
if (i>1) printf(" %d",ans[an]);
else printf("%d",ans[an]);
}
printf("\n");
}
return 0;
}