贪心-会议中心

算法训练 会议中心  
时间限制:2.0s   内存限制:512.0MB
  会议中心  Siruseri政府建造了一座新的会议中心。许多公司对租借会议中心的会堂很感兴趣,他们希望能够在里面举行会议。
  对于一个客户而言,仅当在开会时能够独自占用整个会堂,他才会租借会堂。会议中心的销售主管认为:最好的策略应该是将会堂租借给尽可能多的客户。显然,有可能存在不止一种满足要求的策略。
  例如下面的例子。总共有4个公司。他们对租借会堂发出了请求,并提出了他们所需占用会堂的起止日期(如下表所示)。


开始日期
结束日期
公司1
4
9
公司2
9
11
公司3
13
19
公司4
10
17


  上例中,最多将会堂租借给两家公司。租借策略分别是租给公司1和公司3,或是公司2和公司3,也可以是公司1和公司4。注意会议中心一天最多租借给一个公司,所以公司1和公司2不能同时租借会议中心,因为他们在第九天重合了。
  销售主管为了公平起见,决定按照如下的程序来确定选择何种租借策略:首先,将租借给客户数量最多的策略作为候选,将所有的公司按照他们发出请求的顺序编号。对于候选策略,将策略中的每家公司的编号按升序排列。最后,选出其中字典序最小[1]的候选策略作为最终的策略。
  例中,会堂最终将被租借给公司1和公司3:3个候选策略是{(1,3),(2,3),(1,4)}。而在字典序中(1,3)<(1,4)<(2,3)。
  你的任务是帮助销售主管确定应该将会堂租借给哪些公司。
输入格式
  输入的第一行有一个整数N,表示发出租借会堂申请的公司的个数。第2到第N+1行每行有2个整数。第i+1行的整数表示第i家公司申请租借的起始和终止日期。对于每个公司的申请,起始日期为不小于1的整数,终止日期为不大于10 9的整数。
输出格式
  输出的第一行应有一个整数M,表示最多可以租借给多少家公司。第二行应列出M个数,表示最终将会堂租借给哪些公司。
数据规模和约定
  对于50%的输入,N≤3000。在所有输入中,N≤200000。
样例输入
4
4 9
9 11
13 19
10 17
样例输出
2
1 3

[1] 字典序指在字典中排列的顺序,如果序列l 1是序列l 2的前缀,或者对于l 1和l 2的第一个不同位置j,l 1[j]<l 2[j],则l 1比l 2小。



--摘

#include <iostream>
#include <cmath>
#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <vector>
#include<numeric>
#include <iomanip>
#include <map>
#include <limits.h>
#include <iterator>
#include <sstream>
#include <set>
using namespace std;

const int mi = 19931117;
int lsh[500020], lsht[500020], lshmr;

void initialize (){
    sort(lsh, lsh + lshmr);
    int cnt = 0;
    for (int i = 0; i < lshmr; i++)
    {
        if (i == 0 || lsh[i] != lsh[i - 1])
            lsht[cnt++] = lsh[i];
    } lshmr = cnt;
}
inline int place (int a)
{
    int st = 0, ed = lshmr, mid;
    while (ed - st > 1)
    {
        mid = (st + ed) >> 1;
        if (lsht[mid] > a) ed = mid;
        else st = mid;
    } return st + 1;
}
pair<int, int> require[250010];
pair<int, int> rs[250010], trs[250010]; int trmr;
bool comp (const pair<int, int>& a, const pair<int, int>& b)
{
    if (a.first != b.first) return a.first < b.first;
    else return a.second > b.second;
}

int jump[20][500010], maxj;
void jump_st (void)
{
    int p = 0; jump[0][lshmr + 1] = mi;
    for (int i = lshmr; i >= 1; i--)
    {
        if (p < trmr && i == trs[p].first) jump[0][i] = trs[p++].second + 1;
        else jump[0][i] = jump[0][i + 1];
    }
    bool valid;
    for (int i = 1; ; i++)
    {
        valid = false;
        jump[i][lshmr + 1] = mi;
        for (int k = 1; k <= lshmr; k++)
        {
            if (jump[i - 1][k] == mi) jump[i][k] = mi;
            else jump[i][k] = jump[i - 1][jump[i - 1][k]];
            if (jump[i][k] < mi) valid = true;
        }
        if (valid == false) { maxj = i - 1; break; }
    }
}
int max_time (int s, int e)
{
    if (s >= e) return 0;
    int ts = s, ans = 0; ++e;
    for (int j = maxj; j >= 0 && ts < e; j--)
        if (jump[j][ts] <= e) ts = jump[j][ts], ans += (1 << j);
    return ans;
}
set<pair<int, int> > query;
typedef set<pair<int, int> >::iterator ptr; int ans;
bool judge (int i)
{
    int l = require[i].first, r = require[i].second;
    ptr t1, t2;
    t1 = query.lower_bound(make_pair(l, mi));
    if (t1 == query.begin()) return false; else --t1;
    if (t1->second < l) return false;
    t2 = --query.lower_bound(make_pair(r, mi));
    if (t1 != t2) return false;
    if (t1->second < r) return false;
    int ll = t1->first, rr = t1->second;
    int tans = max_time(ll, l - 1) + max_time(r + 1, rr) + 1;
    int sans = max_time(ll, rr);
    if (tans < sans) return false;
    else
    {
        query.erase(t1);
        if (ll <= l - 1) query.insert(make_pair(ll, l - 1));
        if (r + 1 <= rr) query.insert(make_pair(r + 1, rr));
        return true;
    }
}
int main (){
    int n, ans; scanf("%d", &n), lshmr = 0;
    for (int i = 0; i < n; i++){
        scanf("%d %d", &require[i].first, &require[i].second);
        lsh[lshmr++] = require[i].first;
        lsh[lshmr++] = require[i].second;
    }
    initialize();
    for (int i = 0; i < n; i++)
    {
        int l = place(require[i].first), r = place(require[i].second);
        require[i].first = l, require[i].second = r;
        rs[i] = make_pair(l, r);
    }
    sort(rs, rs + n, comp), trmr = 0; int p;
    for (int i = n - 1; i >= 0; i--)
    {
        if (i == n - 1 || rs[i].second < rs[p].second)
            trs[trmr++] = rs[i], p = i;
    }
    jump_st();
    query.insert(make_pair(1, lshmr));
    printf("%d\n", ans = max_time(1, lshmr));
    for (int i = 0; i < n; i++)
        if (judge(i)) printf("%d ", i + 1);
    printf("\n");
    return 0;
}








评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值