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

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章