很优美的解法。

推荐大佬博客

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

如果一条线段能放入一个区间$[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. ios开发小技巧(转)

    1.通过下面方式可以获取图片的像素颜色点:- (void*)getImageData:(UIImage*)image{    void* imageData;    if (imageData == ...

  2. FAT-fs (mmcblk0p1): Volume was not properly unmounted. Some data may be corrupt. Please run fsck.

    /******************************************************************************** * FAT-fs (mmcblk0p ...

  3. HDU3727 Jewel(主席树+树状数组(或二分))

    Problem Description Jimmy wants to make a special necklace for his girlfriend. He bought many beads ...

  4. RabbitMQ和Kafka可靠性

    RabbitMQ和Kafka可靠性 https://www.cnblogs.com/haolujun/p/9641840.html 我们通过前文知道,RabbitMQ的队列分为master queue ...

  5. 让人蛋疼的“Oracle.DataAccess.dll”

    项目介绍:为前台网站提供rest接口来操作erp相关数据 涉及db:oracle11 技术方案:因为erp是用remoting来调用,我想rest实现部分调用remoting来操作减少耦合,当然性能上 ...

  6. js1

    document.write('<h1>Hello World</h1>'); //写入网页 alert('Hello World'); console.log('Hello ...

  7. 在linux里建立一个快捷方式,连接到另一个目录

    ln -s 源目录 目标快捷方式比如要在/home/下面建立一个叫WIN7的快捷方式,指向/mnt/:ln -s /home/WIN7  /mnt

  8. Linux安装搜狗拼音输入法-sogoupinyin

    Linux安装搜狗拼音输入法-sogoupinyin Linux安装搜狗拼音输入法-sogoupinyin 一.下载所需安装包 二.卸载原有输入法 三.安装 四.安装配置工具 在网上查资料安装好了搜狗 ...

  9. ECMAScript 2016(ES7) 知多少

    ECMAScript 2016(ES7) 知多少 1. 数组方法 Array.prototype.includes(value : any) : boolean 2. 幂运算符 x ** y 扩展阅读 ...

  10. 推荐几个MySQL大牛的博客

    1.淘宝丁奇 http://dinglin.iteye.com/ 2.周振兴@淘宝 花名:苏普 http://www.orczhou.com/ 3. 阿里云数据库高级专家彭立勋为 MariaDB Fo ...