Luogu 3626 [APIO2009]会议中心
很优美的解法。
推荐大佬博客
如果没有保证字典序最小这一个要求,这题就是一个水题了,但是要保证字典序最小,然后我就不会了……
如果一条线段能放入一个区间$[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]会议中心的更多相关文章
- [Luogu P3626] [APIO2009] 会议中心
题面 传送门:https://www.luogu.org/problemnew/show/P3626 Solution 如果题目只要求求出第一问,那这题显然就是大水题. 但是加上第二问的话...... ...
- BZOJ1178或洛谷3626 [APIO2009]会议中心
BZOJ原题链接 洛谷原题链接 第一个问题是经典的最多不相交区间问题,用贪心即可解决. 主要问题是第二个,求最小字典序的方案. 我们可以尝试从\(1\to n\)扫一遍所有区间,按顺序对每一个不会使答 ...
- [APIO2009]会议中心
[APIO2009]会议中心 题目大意: 原网址与样例戳我! 给定n个区间,询问以下问题: 1.最多能够选择多少个不相交的区间? 2.在第一问的基础上,输出字典序最小的方案. 数据范围:\(n \le ...
- 【题解】[APIO2009]会议中心
[题解][P3626 APIO2009]会议中心 真的是一道好题!!!刷新了我对倍增浅显的认识. 此题若没有第二份输出一个字典序的方案,就是一道\(sort+\)贪心,但是第二问使得我们要用另外的办法 ...
- [APIO2009]会议中心(贪心)
P3626 [APIO2009]会议中心 题目描述 Siruseri 政府建造了一座新的会议中心.许多公司对租借会议中心的会堂很 感兴趣,他们希望能够在里面举行会议. 对于一个客户而言,仅当在开会时能 ...
- BZOJ.1178.[APIO2009]会议中心(贪心 倍增)
BZOJ 洛谷 \(Description\) 给定\(n\)个区间\([L_i,R_i]\),要选出尽量多的区间,并满足它们互不相交.求最多能选出多少个的区间以及字典序最小的方案. \(n\leq2 ...
- BZOJ1178 APIO2009 会议中心 贪心、倍增
传送门 只有第一问就比较水了 每一次贪心地选择当前可以选择的所有线段中右端点最短的,排序之后扫一遍即可. 考虑第二问.按照编号从小到大考虑每一条线段是否能够被加入.假设当前选了一个区间集合\(T\), ...
- P3626 [APIO2009]会议中心
传送门 好迷的思路-- 首先,如果只有第一问就是个贪心,排个序就行了 对于第二问,我们考虑这样的一种构造方式,每一次都判断加入一个区间是否会使答案变差,如果不会的话就将他加入别问我正确性我不会证 我们 ...
- 【BZOJ】【1178】【APIO2009】convention会议中心
贪心 如果不考虑字典序的话,直接按右端点排序,能选就选,就可以算出ans…… 但是要算一个字典序最小的解就比较蛋疼了= = Orz了zyf的题解 就是按字典序从小到大依次枚举,在不改变答案的情况下,能 ...
随机推荐
- BEC listen and translation exercise 7
Maybe I ought to subscribe to the Engineering Quarterly.也许我应该订阅<工程学季刊>. The performance is sai ...
- POJ2411Mondriaan's Dream(DP+状态压缩 or 插头DP)
问题: Squares and rectangles fascinated the famous Dutch painter Piet Mondriaan. One night, after prod ...
- web.xml & web-fragment.xml (Servlet 2.3, 2.4, 2.5 + 3.0)模板
转自:http://jlcon.iteye.com/blog/890964 web.xml v2.3 <?xml version="1.0" encoding="I ...
- 开发mis系统用到的技术
1. b/s架构:就broser/server,浏览器/服务器的说法.服务器端要运行tomcat,提供链接数据库服务供java代码读写数据,这个可以在eclipse中配置运行.浏览器则解释jsp或ht ...
- bzoj 4059:Non-boring sequences 分治
题目: 我们害怕把这道题题面搞得太无聊了,所以我们决定让这题超短.一个序列被称为是不无聊的,仅当它的每个连续子序列存在一个独一无二的数字,即每个子序列里至少存在一个数字只出现一次.给定一个整数序列,请 ...
- Codeforces 786C. Till I Collapse 主席树
题目大意: 给定一个长度为\(n\)的序列,要求将其划分为最少的若干段使得每段中不同的数字的种数不超过\(k\). 对于 \(k = 1 .. n\)输出所有的答案. \(n \leq 10^5\) ...
- SpringCloud基础教程学习记录
这个学习记录是学习自翟永超前辈的SpringCloud的基础教程. 自己写这个教程的目的主要是在于,想要更凝练总结一些其中的一些实用点,顺便做个汇总,这样自己在复习查看的时候更加方便,也能顺着自己的思 ...
- think python chapter3
3.1 built-in function type(42)=> <class 'int'> int('32')=>32 int(3.9) => 3 int(-2.3)= ...
- AFN 请求数据https
第一步: 导入afn库 第二步: 在pch中添加 #import <SystemConfiguration/SystemConfiguration.h> #import <Mobil ...
- 【转】火狐浏览器中firebug插件的时间线域解释
又到了上图时间了..对照这张图,各个时间所对应的意义就很简单明了. 阻挡(Blocking):每个浏览器有并发连接数量的上限(例如Firefox对每个host限制6个连接),如果当前建立的连接 ...