zoj3635-Cinema in Akiba 树状数组+二分

来源:互联网 发布:caffe使用指南 编辑:程序博客网 时间:2024/05/29 08:56

     n个人去看电影,正好有n个座位,每个人手中的票上的号码为a[i],表示他进场的时候,需要做到当前从1---n中第a[i]个空位,给出m个查询,分别求出查询的人实际的座位位置。

     用树状数组记录一下每个位置当前是否有人,那么对于一个位置i,就可以求出1---i当中有多少个空位,而i位置也就是当前第i-sum(i)个空位了,由于这个i-sum(i)是单调不减的,所以可以二分位置来求出当前的人应该坐到那个位置上,二分的时候注意一下细节,有一个特殊的情况,就是如果位置i上有人,而查询得到i-sum(i)恰好为求得答案时,此时二分区间应该是在左区间而不是右区间。复杂度n*log(n)*log(n)。

#include <iostream>#include <cstdio>#include <algorithm>#include <cstring>#include <cmath>using namespace std;typedef long long ll;const int maxn=66000;int n,m;int k,x,y;int ans[maxn];struct BIT{    int dt[maxn];    void init()    {        memset(dt,0,sizeof dt);    }    int lowbit(int x)    {        return x&(-x);    }    void add(int x,int c=1)    {        for (int i=x; i<=n; i+=lowbit(i))        dt[i]+=c;    }    int sum(int x)    {        int res=0;        for (int i=x; i>0; i-=lowbit(i))        res+=dt[i];        return res;    }}bit;int check(int k,int x){    int tp=bit.sum(k);    return k-bit.sum(k);}bool flag[maxn];int find(int x){    int l=0,r=n+1;    int res=0;    int mid;    while(l<r)    {        mid=(l+r)>>1;        int ct=check(mid,x);        if (ct==x)        {            if (!flag[mid]) return mid;            else            {                r=mid;            }        }        else if (ct<x) l=mid+1;        else r=mid;    }    return res;}int main(){//    freopen("in.txt","r",stdin);    while(~scanf("%d",&n))    {        bit.init();        memset(flag,false,sizeof flag);        for (int i=1; i<=n; i++)        {            scanf("%d",&k);            ans[i]=find(k);            bit.add(ans[i]);            flag[ans[i]]=true;        }        scanf("%d",&m);        scanf("%d",&k);        cout<<ans[k];        for (int i=1; i<m; i++)        {            scanf("%d",&k);            cout<<" "<<ans[k];        }        cout<<endl;    }    return 0;}


0 0
原创粉丝点击