很优美的解法。

推荐大佬博客

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

如果一条线段能放入一个区间$[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. @angular/cli项目构建--modal

    环境准备: cnpm install ngx-bootstrap-modal --save-dev impoerts: [BootstrapModalModule.forRoot({container ...

  2. PHP Smarty template for website

    /****************************************************************************** * PHP Smarty templat ...

  3. LeetCode Can Place Flowers

    原题链接在这里:https://leetcode.com/problems/can-place-flowers/description/ 题目: Suppose you have a long flo ...

  4. 洛谷 P3223 [HNOI2012]排队

    题目描述 某中学有 n 名男同学,m 名女同学和两名老师要排队参加体检.他们排成一条直线,并且任意两名女同学不能相邻,两名老师也不能相邻,那么一共有多少种排法呢?(注意:任意两个人都是不同的) 输入输 ...

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

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

  6. bzoj 3027 [Ceoi2004]Sweet——生成函数

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=3027 化式子到 ( \mul_{i=1}^{n}(1-x^(m[i]+1)) ) / (1- ...

  7. 【转】 Pro Android学习笔记(八五):了解Package(4):lib项目

    目录(?)[-] 什么是lib项目 小例子 Lib的实现 文章转载只能用于非商业性质,且不能带有虚拟货币.积分.注册等附加条件.转载须注明出处:http://blog.csdn.net/flowing ...

  8. javascript一些小的注意点

    try...catch 可以测试代码中的错误.try 部分包含需要运行的代码,而 catch 部分包含错误发生时运行的代码. 当try { 里面的代码 出现错误了 }catch(e){ 才执行下面的c ...

  9. pyodbc连接MySQL数据库

    1:Python安装pyodbc:pip install pyodbc 2:安装unixODBC-2.3.4.tar.gz ./configure make make install 3:下载基于py ...

  10. javascript——作用域与闭包

    http://www.cnblogs.com/lucio-yr/p/4047972.html 一.作用域: 在函数内部:用 var 声明的表示局部变量,未用var的是全局变量. 作用域取决于变量定义时 ...