H - Pavel's Party ( 权值线段树 + 思维 )

H - Pavel's Party ( 权值线段树 + 思维 )

题目链接:https://vjudge.net/problem/Gym-100971H

题意:Pavel 将要举行一个聚会,他想确切地邀请k个人参加。他有n个朋友,并且他已经决定按什么顺序打电话和邀请他们,每个朋友会回复他两个值 l 和 r,代表如果这个聚会的人数在[ l, r ] 之间他就会参加。Pavel一旦集合了所需的人数,就会立刻开启聚会,不会给其余的朋友打电话。询问k为1~n时,分别,最少需要给前多少人打电话。如果给n个朋友全打完也凑不到人就输出-1.

Input

6
3 3
1 2
3 6
3 4
1 4
4 6

Output

2 5 4 6 -1 -1

样例解释:6个朋友,分别给出ai bi,

输出的2表示当Pavel准备组织1个人的聚会需要给前2个人打电话。

输出的5表示当Pavel准备组织2个人的聚会需要给前5个人打电话。

输出的4表示当Pavel准备组织3个人的聚会需要给前4个人打电话。

输出的6表示当Pavel准备组织4个人的聚会需要给前6个人打电话。

 

思路:我们做一颗权值线段树维护所有人的编号。当为1时,表示这个人可以来; 为0时,表示  这个人没发来。准备两个数组(里面存每个人的 l ,r,id),一个是左边界升序(a数组),一个是右边界升序(b数组)。

然后for循环从1到n枚举Pavel准备组织k个人。当枚举到k时,把a数组里 l 等于k的加入权值线段树。 把b数组里 r 等于k的从权值线段树里删除。在中间更新ans[ k ] = -1, 或者是线段树里第 k 个人的编号。

代码:

#include <bits/stdc++.h>
#define mid ((left+right)/2)
#define lson node*2,left,mid
#define rson node*2+1,mid+1,right

using namespace std;

struct node {
    int l,r,id;
}a[200005],b[200005];
int n;
int tree[200005*4]; /// 维护人的编号
int ans[200005];

int rule( node a, node b ) {return a.l<b.l;}
int rule2( node a, node b ) {return a.r<b.r;}

void update( int node, int left, int right, int id, int val )
{
    if ( left==right ) {
        tree[node] += val;
        return ;
    }
    if ( id<=mid ) update(lson,id,val);
    if ( id>mid )  update(rson,id,val);
    tree[node] = tree[node*2] + tree[node*2+1];
}

int query( int node, int left, int right, int k ) /// 返回第k个人的编号
{
    if ( left==right ) return left;
    if ( tree[node*2]>=k ) return query(lson,k);
    else return query(rson,k-tree[node*2]);
}

int main()
{
    cin >> n;
    for ( int i=1; i<=n; i++ ) {
        scanf("%d %d",&a[i].l,&a[i].r);
        a[i].id = i;
        b[i] = a[i];
    }
    sort(a+1,a+1+n,rule);  /// 加入的人
    sort(b+1,b+1+n,rule2); /// 删除的人
    memset(tree,0,sizeof(tree));
    int posa = 1, posb = 1;
    for ( int k=1; k<=n; k++ ) {
        while ( posa<=n && a[posa].l==k ) {  /// 插入
            update(1,1,n,a[posa].id,1);
            posa++;
        }
        if ( tree[1]<k ) ans[k] = -1;  
        else ans[k] = query(1,1,n,k);  /// 更新答案
        while ( posb<=n && b[posb].r==k ) {  /// 删除
            update(1,1,n,b[posb].id,-1);
            posb++;
        }
    }
    for ( int i=1; i<=n; i++ ) cout << ans[i] << " ";

    return 0;
}

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值