很优美的解法。

推荐大佬博客

如果没有保证字典序最小这一个要求,这题就是一个水题了,但是要保证字典序最小,然后我就不会了……

如果一条线段能放入一个区间$[l', r']$并且不影响最优答案,那么对于这条线段$[l, r]$,设$solve(l, r)$表示$[l, r]$这个区间里面最多能放多少条线段,一定要有条件$solve(l', l - 1) + solve(r + 1, r') + 1 == solve(l', r')$。

那么贪心的时候顺便考虑一下怎么检验的问题就可以了,如果暴力检验是$O(n)$的,考虑优化,利用一下倍增思想,我们设$f_{i, j}$表示从$i$开始选择$2^{j}$条线段所能到达的最靠左的右端点,那么在离散化之后就可以用$O(nlogn)$的时间预处理出$f$数组,这样子每一次检验求$solve$的时间是$O(logn)$的,具体怎么处理可以参照下面的代码。

考虑一下最后怎么进行的贪心,对于每一条线段,我们检验一下是不是能放,这个检验的过程可以用很多数据结构做到$O(logn)$,如果能放入,我们就找出之前放过的最前的右端点和最后的左端点,然后chk一下上面的条件是否成立就可以了。

感觉这个过程写个线段树更直观一点,还是学习了一下上面那位大佬高能的树状数组写法。

时间复杂度$O(nlogn)$。

Code:

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std; const int N = 2e5 + ;
const int Lg = ;
const int inf = << ; int n, tot = , maxn = ;
int l[N], r[N], f[N << ][Lg];
int ans[N], lmax[N << ], rmax[N << ], lsum[N << ], rsum[N << ]; struct Innum {
int val, id;
} in[N << ]; bool cmpIn(const Innum &x, const Innum &y) {
if(x.val != y.val) return x.val < y.val;
else return x.id < y.id;
} inline void read(int &X) {
X = ; char ch = ; int op = ;
for(; ch > ''|| ch < ''; ch = getchar())
if(ch == '-') op = -;
for(; ch >= '' && ch <= ''; ch = getchar())
X = (X << ) + (X << ) + ch - ;
X *= op;
} inline int max(int x, int y) {
return x > y ? x : y;
} inline int min(int x, int y) {
return x > y ? y : x;
} inline void chkMax(int &x, int y) {
if(y > x) x = y;
} inline void discrete() {
sort(in + , in + + tot, cmpIn);
for(int cnt = , i = ; i <= tot; i++) {
if(in[i].val != in[i - ].val) ++cnt;
maxn = max(maxn, cnt);
if(in[i].id > n) r[in[i].id - n] = cnt;
else l[in[i].id] = cnt;
}
} #define lowbit(x) ((x) & (-x)) inline void aSum(int *now, int x) {
for(; x <= maxn; x += lowbit(x))
++now[x];
} inline int qSum(int *now, int x) {
int res = ;
for(; x > ; x -= lowbit(x))
res += now[x];
return res;
} inline void aMax(int *now, int x) {
for(int t = x; x <= maxn; x += lowbit(x))
chkMax(now[x], t);
} inline int qMax(int *now, int x) {
int res = ;
for(; x > ; x -= lowbit(x))
chkMax(res, now[x]);
return res;
} inline int solve(int ln, int rn) {
int res = ;
for(int i = ; i >= ; i--)
if(f[ln][i] <= rn) res += ( << i), ln = f[ln][i] + ;
return res;
} int main() {
read(n);
for(int i = ; i <= n; i++) {
read(l[i]), read(r[i]);
in[++tot] = (Innum) {l[i], i};
in[++tot] = (Innum) {r[i], i + n};
}
discrete(); memset(f, 0x7f, sizeof(f));
for(int i = ; i <= n; i++)
f[l[i]][] = min(f[l[i]][], r[i]);
for(int i = maxn; i >= ; i--) {
f[i][] = min(f[i][], f[i + ][]);
for(int j = ; f[i][j - ] <= maxn && ( << j) <= n; j++)
f[i][j] = f[f[i][j - ] + ][j - ];
} /* for(int i = 1; i <= maxn; i++)
printf("%d ", f[i][0]);
printf("\n"); */ /* for(int i = 1; i <= n; i++)
printf("%d %d\n", l[i], r[i]);
printf("\n"); */ tot = ;
for(int i = ; i <= n; i++) {
int v = tot - qSum(rsum, l[i] - ) - qSum(lsum, maxn - r[i]);
if(v > ) continue;
int lst = qMax(rmax, l[i] - ), nxt = maxn - qMax(lmax, maxn - r[i]);
if(solve(lst + , l[i] - ) + solve(r[i] + , nxt) + == solve(lst + , nxt)) {
ans[++tot] = i;
aSum(rsum, r[i]), aSum(lsum, maxn - l[i] + );
aMax(rmax, r[i]), aMax(lmax, maxn - l[i] + );
} // printf("%d ", v);
}
// printf("\n"); printf("%d\n", tot);
for(int i = ; i <= tot; i++)
printf("%d ", ans[i]);
printf("\n"); return ;
}

Luogu 3626 [APIO2009]会议中心的更多相关文章

  1. [Luogu P3626] [APIO2009] 会议中心

    题面 传送门:https://www.luogu.org/problemnew/show/P3626 Solution 如果题目只要求求出第一问,那这题显然就是大水题. 但是加上第二问的话...... ...

  2. BZOJ1178或洛谷3626 [APIO2009]会议中心

    BZOJ原题链接 洛谷原题链接 第一个问题是经典的最多不相交区间问题,用贪心即可解决. 主要问题是第二个,求最小字典序的方案. 我们可以尝试从\(1\to n\)扫一遍所有区间,按顺序对每一个不会使答 ...

  3. [APIO2009]会议中心

    [APIO2009]会议中心 题目大意: 原网址与样例戳我! 给定n个区间,询问以下问题: 1.最多能够选择多少个不相交的区间? 2.在第一问的基础上,输出字典序最小的方案. 数据范围:\(n \le ...

  4. 【题解】[APIO2009]会议中心

    [题解][P3626 APIO2009]会议中心 真的是一道好题!!!刷新了我对倍增浅显的认识. 此题若没有第二份输出一个字典序的方案,就是一道\(sort+\)贪心,但是第二问使得我们要用另外的办法 ...

  5. [APIO2009]会议中心(贪心)

    P3626 [APIO2009]会议中心 题目描述 Siruseri 政府建造了一座新的会议中心.许多公司对租借会议中心的会堂很 感兴趣,他们希望能够在里面举行会议. 对于一个客户而言,仅当在开会时能 ...

  6. BZOJ.1178.[APIO2009]会议中心(贪心 倍增)

    BZOJ 洛谷 \(Description\) 给定\(n\)个区间\([L_i,R_i]\),要选出尽量多的区间,并满足它们互不相交.求最多能选出多少个的区间以及字典序最小的方案. \(n\leq2 ...

  7. BZOJ1178 APIO2009 会议中心 贪心、倍增

    传送门 只有第一问就比较水了 每一次贪心地选择当前可以选择的所有线段中右端点最短的,排序之后扫一遍即可. 考虑第二问.按照编号从小到大考虑每一条线段是否能够被加入.假设当前选了一个区间集合\(T\), ...

  8. P3626 [APIO2009]会议中心

    传送门 好迷的思路-- 首先,如果只有第一问就是个贪心,排个序就行了 对于第二问,我们考虑这样的一种构造方式,每一次都判断加入一个区间是否会使答案变差,如果不会的话就将他加入别问我正确性我不会证 我们 ...

  9. 【BZOJ】【1178】【APIO2009】convention会议中心

    贪心 如果不考虑字典序的话,直接按右端点排序,能选就选,就可以算出ans…… 但是要算一个字典序最小的解就比较蛋疼了= = Orz了zyf的题解 就是按字典序从小到大依次枚举,在不改变答案的情况下,能 ...

随机推荐

  1. AtCoder Beginner Contest 087 D - People on a Line

    Time limit : 2sec / Memory limit : 256MB Score : 400 points Problem Statement There are N people sta ...

  2. [SPOJ10707]Count on a tree II

    luogu 题意 给定一个n个节点的树,每个节点表示一个整数,问u到v的路径上有多少个不同的整数. sol 也就是路径数颜色.树上莫队板子题. 我这种分块的姿势貌似是假的. 所以跑的是最慢的QAQ. ...

  3. LeetCode Construct String from Binary Tree

    原题链接在这里:https://leetcode.com/problems/construct-string-from-binary-tree/#/description 题目: You need t ...

  4. I would I were a careless child

    I would I were a careless child by George Gordon Byron 1 I would I were a careless child, still dwel ...

  5. C#中将dateTimePicker初始值设置为空

    最近在做一个小项目,有一个功能是根据用户选择条件查询数据,要求时间控件的默认值为空,只有当用户修改了时间,才根据时间查询.简单的说,就是默认或者点击清空按钮的情况下,时间控件dateTimePicke ...

  6. 使用bat文件实现批量重命名功能

    在生活中我们总会碰到对大量文件进行重命名操作,这时如果一个一个的,选取文件→右键→重命名→选取文件,这样操作势必会浪费大量时间. 现在小编就告诉大家一个使用bat文件(命令行)的方法,快速对文件进行重 ...

  7. 一、Jmeter的安装

    一.首先安装Jmeter 1.安装java Jmeter是使用java实现的测试工具,在安装Java之前我们需要安装java. 到这里去下载相应的JDK:https://www.java.com/en ...

  8. nginx与二级域名的绑定 nginx安装

    nginx中文文档 http://www.nginx.cn/doc/ nginx 查看配置文件地址 http://blog.csdn.net/ljfrocky/article/details/5052 ...

  9. linux下redis服务器安装使用 安装php的redis扩展 安装laravel下的redis

    linux下redis服务器安装使用 学习源头: https://blog.csdn.net/itmanba/article/details/77335012 安装完毕试运行redis的时候,可能会出 ...

  10. 备注信息的textarea 和 数据库 text类型

    有时候需要用到备注信息 备注一些东西 但是它又不同于普通的输入框,要有换行啊 空格之类的,更有甚者还有其他更多的需求 1.更多需求 用富文本编辑器 2.普通需求 直接用input type=" ...