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;
}