• [BZOJ1178][Apio2009]CONVENTION会议中心


    [BZOJ1178][Apio2009]CONVENTION会议中心

    试题描述

    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个数,表示最终将会堂租借给哪些公司。

    输入示例

    4
    4 9
    9 11
    13 19
    10 17

    输出示例

    2
    1 3 

    数据规模及约定

    对于50%的输入,N≤3000。在所有输入中,N≤200000 请注意使用Readln读入数据........

    题解

    这里把所有的“公司”等价成左端点为“开始日期”,右端点为“结束日期”的线段。

    如果只考虑第一问,贪心即可,按右端点升序排序,把所有包含别的线段的线段去掉数个数即可。

    加了个字典序,就好玩了。

    然而“字典序”还是要用到贪心,于是从1~n条线段依次判断,若第 i 条线段满足加进去后不影响最终能选的线段条数则毫无疑问地选择 i。如何判断是核心问题,我们可以用倍增算法:令 f(j, i) 表示从点 i 开始,选择 2j 个不相交线段可能的最靠左的点,那么就不难算出一个区间 [L, R] 中最优能选择的线段条数了(详见代码中的 getans() 函数)。以后判断线段时,先确保当前线段与前面所有加进来的线段无交集,再找到这个线段的前驱 ql 和后继 qr,然后当 ans(ql + 1, qr - 1) = ans(ql + 1, l - 1) + 1 + ans(r + 1, qr - 1) 时说明这个线段可以选进来(ans(i, j)表示区间[i, j]中最优能够选择的线段的条数,l、r 表示当前线段左、右端点)。

    至于判断线段是否有交集,可以用个平衡树找前驱后继。(如果不怕慢可以用set)

    代码注释多,请忽略。

    #include <iostream>
    #include <cstdio>
    #include <algorithm>
    #include <cmath>
    #include <stack>
    #include <vector>
    #include <queue>
    #include <cstring>
    #include <string>
    #include <map>
    #include <set>
    using namespace std;
    
    const int BufferSize = 1 << 16;
    char buffer[BufferSize], *Head, *tail;
    inline char Getchar() {
        if(Head == tail) {
            int l = fread(buffer, 1, BufferSize, stdin);
            tail = (Head = buffer) + l;
        }
        return *Head++;
    }
    int read() {
        int x = 0, f = 1; char c = Getchar();
        while(!isdigit(c)){ if(c == '-') f = -1; c = Getchar(); }
        while(isdigit(c)){ x = x * 10 + c - '0'; c = Getchar(); }
        return x * f;
    }
    
    #define maxn 200010
    #define maxm 400010
    #define maxlog 20
    #define oo 2147483647
    int n, N, cnt, num[maxm], c, ans[maxn];
    struct Line { int l, r, id; } ls[maxn];
    
    int Right[maxlog][maxm];
    void init() {
    	for(int j = 1; j < maxlog; j++)
    		for(int i = 1; i <= N && Right[j-1][i] < N && Right[j-1][Right[j-1][i]+1] <= N; i++)
    			Right[j][i] = Right[j-1][Right[j-1][i]+1];
    	return ;
    }
    int getans(int l, int r) {
    	if(l > r) return 0;
    	int ans = 0, p = l;
    	for(int i = maxlog-1; i >= 0; i--) if(Right[i][p] <= r)
    		ans += (1 << i), p = Right[i][p];
    	return ans;
    }
    
    int ToT, fa[maxm], ch[maxm][2], root;
    struct Node { int v, r, minv, maxv, siz; } nodes[maxm];
    void newnode(int& o, int v) {
    	nodes[o = ++ToT] = (Node) { v, rand(), v, v, 1 };
    	return ;
    }
    void maintain(int o) {
    	Node &u = nodes[o], &lc = nodes[ch[o][0]], &rc = nodes[ch[o][1]];
    	u.minv = min(min(lc.minv, rc.minv), u.v);
    	u.maxv = max(max(lc.maxv, rc.maxv), u.v);
    	u.siz = lc.siz + 1 + rc.siz;
    	return ;
    }
    void rotate(int u) {
    	int y = fa[u], z = fa[y], l = 0, r = 1;
    	if(ch[y][1] == u) swap(l, r);
    	if(z >= 0) ch[z][ch[z][1]==y] = u;
    	else root = u;
    	fa[u] = z; fa[y] = u; fa[ch[u][r]] = y;
    	ch[y][l] = ch[u][r]; ch[u][r] = y;
    	maintain(y); maintain(u);
    	return ;
    }
    void insert(int& o, int v, int pa) {
    	if(!o) {
    		newnode(o, v);
    		fa[o] = pa;
    		return ;
    	}
    	int d = v > nodes[o].v;
    	insert(ch[o][d], v, o);
    	if(nodes[ch[o][d]].r > nodes[o].r) rotate(ch[o][d]);
    	maintain(o);
    	return ;
    }
    int _l, _r, _s;
    void findp(int o, int v) {
    //	printf("
    o: %d %d %d %d
    ", o, nodes[o].v, ch[o][0], nodes[ch[o][0]].maxv);
    	if(!o) { _l = _r = -1; return ; }
    	if(nodes[o].v == v){ _l = _r = v; return ; }
    	if(nodes[o].v > v && ch[o][0] && nodes[ch[o][0]].maxv < v) {
    		_s += nodes[ch[o][0]].siz;
    		_l = nodes[ch[o][0]].maxv; _r = nodes[o].v;
    		return ;
    	}
    	if(nodes[o].v < v && ch[o][1] && nodes[ch[o][1]].minv > v) {
    		_s += nodes[ch[o][0]].siz + 1;
    		_l = nodes[o].v; _r = nodes[ch[o][1]].minv;
    		return ;
    	}
    	int d = v > nodes[o].v;
    	if(d) _s += nodes[ch[o][0]].siz + 1;
    	findp(ch[o][d], v);
    	return ;
    }
    
    int main() {
    //	freopen("data.in", "r", stdin);
    //	freopen("data.out", "w", stdout);
    	srand(1314);
    	n = read(); N = n << 1;
    	for(int i = 1; i <= n; i++) {
    		num[++cnt] = ls[i].l = read(); num[++cnt] = ls[i].r = read();
    		ls[i].id = i;
    	}
    	sort(num + 1, num + cnt + 1);
    	unique(num + 1, num + cnt + 1);
    	for(int i = 1; i <= n; i++) {
    		ls[i].l = lower_bound(num + 1, num + cnt + 1, ls[i].l) - num;
    		ls[i].r = lower_bound(num + 1, num + cnt + 1, ls[i].r) - num;
    	}
    	
    	int p = 0;
    	for(int j = 0; j < maxlog; j++)
    		for(int i = 1; i <= N; i++) Right[j][i] = N + 1;
    	for(int i = 1; i <= n; i++) Right[0][ls[i].l] = min(Right[0][ls[i].l], ls[i].r);
    //	for(int i = 1; i <= n; i++) printf("%d %d
    ", ls[i].l, ls[i].r);
    	for(int i = N - 1; i; i--) Right[0][i] = min(Right[0][i], Right[0][i+1]);
    //	for(int i = 1; i <= N; i++) printf("%d ", Right[0][i]); putchar('
    ');
    	init();
    	printf("%d
    ", getans(1, N));
    	nodes[0] = (Node) { 0, 0, oo, -oo, 0 };
    	insert(root, 0, -1); insert(root, N + 1, -1);
    	for(int i = 1; i <= n; i++) {
    		findp(root, ls[i].l); int ll = _l, lr = _r; _s = 0;
    		findp(root, ls[i].r); int rl = _l, rr = _r;
    //		printf("%d [%d, %d]: %d %d %d %d %d
    ", i, ls[i].l, ls[i].r, ll, lr, rl, rr, _s);
    		if(ll == lr || rl == rr || ll != rl || lr != rr || !(_s & 1)) continue;
    		ll++; lr--;
    		if(getans(ll, lr) == getans(ll, ls[i].l-1) + 1 + getans(ls[i].r+1, lr)) {
    			ans[++c] = i; insert(root, ls[i].l, -1); insert(root, ls[i].r, -1);
    		}
    	}
    //	printf("getans: %d %d
    ", getans(1, 3), Right[0][1]);
    	
    	for(int i = 1; i <= c; i++) printf("%d ", ans[i]); putchar('
    ');
    //	printf("%d
    ", c);
    	
    	return 0;
    }
    /*
    5
    4 8
    3 6
    1 4
    1 3
    9 10
    */
    
  • 相关阅读:
    List
    集合
    layui树状组件tree回显如果子节点选中,当前主节点下所有元素都会选中问题修复
    layui富文本编辑器提交时无法获取到值
    thinkphp6+layui富文本编辑器页面回显显示HTML标签
    layui获取树形菜单所有选中的值
    php7将二维数组转为树状数组
    jq处理img标签找不到图片,显示指定图片
    thinkphp6根据访问设备不同访问不同模块
    layui怎么进入页面监听select的值然后重新渲染页面
  • 原文地址:https://www.cnblogs.com/xiao-ju-ruo-xjr/p/5428338.html
Copyright © 2020-2023  润新知