GYM 100971 H.Pavel's Party(BIT)

Description
一个人想邀请k个朋友来做客,给第i个朋友打电话他会告诉一个[ai,bi]表示包括这个人自己在内有ai到bi个人去这个人就会去,每次打电话都是从第一个朋友开始按顺序打,叫够k个人就不打电话了,问对1~n中每个k要打多少个电话恰能邀请到k个人
Input
第一行一整数n表示朋友数量,之后n行两个整数ai和bi表示该朋友去做客对人数的要求(1<=n<=2e5,1<=ai<=bi<=n)
Output
输出n个数表示k从1取到n时至少需要打多少电话才能叫到k个人,如果给n个人打电话后也叫不齐k个人则输出-1
Sample Input
6
3 3
1 2
3 6
3 4
1 4
4 6
Sample Output
2 5 4 6 -1 -1
Solution
对于每个要求[ai,bi]用两个二元组(ai,-i)和(bi,i)来表示,对这些二元组排序(第一维升序,第一维相等则第二维升序),对于每个k,把所有第一维不大于k第二维为负的二元组插到BIT中(这些二元组表示叫k个人做客时可以来的客人,插入的时候如果是第二维为-i则在i位置插入1表示这个人会来,如果第二维为i则在i位置插入-1表示这个人不会来),那么对任一x,在BIT中求一个1~x的前缀和就表示如果给前x个人打电话可以叫到多少人来做客,我们要求的是使得前缀和恰为k的x,那么我们从高往低给x的二进制位赋值,如果当前位赋为1后前缀和小于k则赋1否则赋0,那么我们得到了使得前缀和不大于k的最大x,如果1~x的前缀和小于k则给x加一,此时如果1~x的前缀和等于k说明给前x个人打电话即可,否则说明无解(这种情况就是当前BIT中所有数加起来小于k,也即给所有人打电话也叫不齐k个人),当对于一个k的答案求完之后,要把所有第一维不大于k第二维为正的二元组插到BIT中表示消除右端点小于等于k的人对后面答案的影响
Code

#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<vector>
#include<queue>
#include<map>
#include<set>
#include<ctime>
using namespace std;
typedef long long ll;
#define INF 0x3f3f3f3f
#define maxn 222222
struct BIT
{
    #define lowbit(x) (x&(-x))
    int b[maxn],n;
    void init(int _n)
    {
        memset(b,0,sizeof(b));
        n=_n;
    }
    void update(int x,int v)
    {
        while(x<=n)
        {
            b[x]+=v;
            x+=lowbit(x);
        }
    }
    int query(int x)
    {
        if(x>n)return INF;
        int ans=0;
        while(x)
        {
            ans+=b[x];
            x-=lowbit(x);
        }
        return ans;
    } 
}bit;
typedef pair<int,int>P;
P a[2*maxn];
int n;
int main()
{
    while(~scanf("%d",&n))
    {
        bit.init(n);
        int res=0;
        for(int i=1;i<=n;i++)
        {
            int l,r;
            scanf("%d%d",&l,&r);
            a[res++]=P(l,-i),a[res++]=P(r,i);
        }
        sort(a,a+res);
        for(int k=1,cnt=0;k<=n;k++)
        {
            while(cnt<res&&a[cnt].second<0&&a[cnt].first<=k)bit.update(-a[cnt].second,1),cnt++;
            int ans=0;
            for(int i=(1<<18);i;i>>=1)
                if(bit.query(ans|i)<k)ans|=i;
            if(bit.query(ans)<k)ans++;
            if(bit.query(ans)==k)printf("%d",ans);
            else printf("-1");
            printf("%c",k==n?'\n':' ');
            while(cnt<res&&a[cnt].second>0&&a[cnt].first<=k)bit.update(a[cnt].second,-1),cnt++;
        }
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值