BZOJ1178 APIO2009 会议中心 贪心、倍增
只有第一问就比较水了
每一次贪心地选择当前可以选择的所有线段中右端点最短的,排序之后扫一遍即可。
考虑第二问。按照编号从小到大考虑每一条线段是否能够被加入。假设当前选了一个区间集合\(T\),当前正在考虑第\(i\)个区间\((l_i,r_i)\)能否被加入。假如集合\(T\)中存在一个区间\((l_j,r_j)\)与\((l_i,r_i)\)有交,那么显然这个区间不能被放进去。
如果说不存在这样的区间,考虑集合\(T\)中区间\((l_i,r_i)\)的前驱\((l_p,r_p)\)和后继\((l_q,r_q)\)。那么\((l_i,r_i)\)能够被加入的充要条件是:\(f(r_p+1,l_i-1) + f(r_i+1 , l_q - 1) + 1 = f(r_p + 1 , l_q - 1)\),其中\(f(i,j)\)表示只选择被包含于区间\([i,j]\)的区间,最多能够选择多少个区间。
显然我们不能每一次\(O(n)\)地计算\(f\)函数,考虑其他的方法。
在所有区间中,去掉包含了其他区间的区间。那么这些区间按照左端点排序后,左端点递增,右端点也递增。我们在这样的区间上贪心时,就可以对所有区间扫一遍,每一次能选即选。
注意到选中了某一个区间之后,下一次选中的区间是固定的,故考虑倍增优化。
设\(jmp_{i,j}\)表示从第\(i\)个区间开始向右选择,选择到的\(2^j\)个区间的编号,不难使用双指针预处理。
接下来考虑计算\(f(l,r)\)。通过二分查找找到左端点\(\geq l\)的最左端的区间\(x\),那么如果\(r_x \leq r\),\(x\)一定是会被选中的。而选中\(x\)之后接下来贪心选择的所有区间都可以通过倍增知道。那么倍增找到接下来选择的所有区间中右端点\(\leq r\)的最右段的区间并记录总共经过多少个区间即可。
对于区间集合\(T\)可以使用\(set\)维护。值得注意的是std::lower_bound在set等不支持随机访问的STL下复杂度不正确,请使用std::set::lower_bound。
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<ctime>
#include<cctype>
#include<algorithm>
#include<cstring>
#include<iomanip>
#include<queue>
#include<map>
#include<set>
#include<bitset>
#include<stack>
#include<vector>
#include<cmath>
#include<random>
//This code is written by Itst
using namespace std;
inline int read(){
int a = 0;
char c = getchar();
while(!isdigit(c))
c = getchar();
while(isdigit(c)){
a = a * 10 + c - 48;
c = getchar();
}
return a;
}
const int MAXN = 2e5 + 3;
struct line{
int l , r , ind;
bool operator <(const line a)const{
return l < a.l || l == a.l && r < a.r;
}
}now[MAXN] , L[MAXN];
set < line > S;
set < line > :: iterator itS;
int N , cnt , cntL , jump[MAXN][21];
bool cmp(line a , line b){
return a.ind < b.ind;
}
void init(){
int minN = 1;
sort(now + 1 , now + N + 1);
for(int i = 1 ; i <= N ; ++i){
if(now[minN].r < now[i].l){
++cnt;
minN = i;
}
else
if(now[minN].r > now[i].r)
minN = i;
}
++cnt;
minN = 1e9;
for(int i = N ; i ; --i)
if(now[i].r < minN){
minN = now[i].r;
L[cntL++] = now[i];
}
reverse(L , L + cntL);
int p = cntL - 1;
for(int i = cntL - 1 ; i >= 0 ; --i){
while(p > i && L[p].l > L[i].r)
--p;
jump[i][0] = p == cntL - 1 ? -1 : p + 1;
for(int j = 1 ; j <= 19 ; ++j)
jump[i][j] = jump[i][j - 1] == -1 ? -1 : jump[jump[i][j - 1]][j - 1];
}
}
int query(int l , int r){
int t = lower_bound(L , L + cntL , (line){l , 0}) - L;
if(t == cntL || L[t].r > r)
return 0;
int sum = 0;
for(int i = 19 ; i >= 0 ; --i)
if(jump[t][i] != -1 && L[jump[t][i]].r <= r){
sum += 1 << i;
t = jump[t][i];
}
return sum + 1;
}
#define INF 2e9
int main(){
#ifndef ONLINE_JUDGE
freopen("in","r",stdin);
freopen("out","w",stdout);
#endif
N = read();
for(int i = 1 ; i <= N ; ++i){
now[i].l = read();
now[i].r = read();
now[i].ind = i;
}
init();
printf("%d\n" , cnt);
sort(now + 1 , now + N + 1 , cmp);
for(int i = 1 ; i <= N && cnt ; ++i){
int L , R;
itS = S.lower_bound(now[i]);
if(itS == S.end())
R = INF;
else
if(itS->l > now[i].r)
R = itS->l - 1;
else
continue;
if(itS == S.begin())
L = 0;
else
if((--itS)->r < now[i].l)
L = itS->r + 1;
else
continue;
if(query(L , now[i].l - 1) + query(now[i].r + 1 , R) + 1 == query(L , R)){
printf("%d " , i);
S.insert(now[i]);
--cnt;
}
}
return 0;
}
BZOJ1178 APIO2009 会议中心 贪心、倍增的更多相关文章
- BZOJ.1178.[APIO2009]会议中心(贪心 倍增)
BZOJ 洛谷 \(Description\) 给定\(n\)个区间\([L_i,R_i]\),要选出尽量多的区间,并满足它们互不相交.求最多能选出多少个的区间以及字典序最小的方案. \(n\leq2 ...
- [APIO2009]会议中心(贪心)
P3626 [APIO2009]会议中心 题目描述 Siruseri 政府建造了一座新的会议中心.许多公司对租借会议中心的会堂很 感兴趣,他们希望能够在里面举行会议. 对于一个客户而言,仅当在开会时能 ...
- [APIO2009]会议中心
[APIO2009]会议中心 题目大意: 原网址与样例戳我! 给定n个区间,询问以下问题: 1.最多能够选择多少个不相交的区间? 2.在第一问的基础上,输出字典序最小的方案. 数据范围:\(n \le ...
- 【题解】[APIO2009]会议中心
[题解][P3626 APIO2009]会议中心 真的是一道好题!!!刷新了我对倍增浅显的认识. 此题若没有第二份输出一个字典序的方案,就是一道\(sort+\)贪心,但是第二问使得我们要用另外的办法 ...
- BZOJ1178 [Apio2009]CONVENTION会议中心 贪心 set
欢迎访问~原文出处——博客园-zhouzhendong 去博客园看该题解 题目传送门 - BZOJ1178 题意概括 一堆线段,现在取出最多条数,使其互不覆盖,并输出字典序最小的方案. 题解 这题好坑 ...
- BZOJ1178或洛谷3626 [APIO2009]会议中心
BZOJ原题链接 洛谷原题链接 第一个问题是经典的最多不相交区间问题,用贪心即可解决. 主要问题是第二个,求最小字典序的方案. 我们可以尝试从\(1\to n\)扫一遍所有区间,按顺序对每一个不会使答 ...
- bzoj1178/luogu3626 会议中心 (倍增+STL::set)
贪心地,可以建出一棵树,每个区间对应一个点,它的父亲是它右边的.与它不相交的.右端点最小的区间. 为了方便,再加入一个[0,0]区间 于是就可以倍增来做出从某个区间开始,一直到某个右界,这之中最多能选 ...
- Luogu 3626 [APIO2009]会议中心
很优美的解法. 推荐大佬博客 如果没有保证字典序最小这一个要求,这题就是一个水题了,但是要保证字典序最小,然后我就不会了…… 如果一条线段能放入一个区间$[l', r']$并且不影响最优答案,那么对于 ...
- P3626 [APIO2009]会议中心
传送门 好迷的思路-- 首先,如果只有第一问就是个贪心,排个序就行了 对于第二问,我们考虑这样的一种构造方式,每一次都判断加入一个区间是否会使答案变差,如果不会的话就将他加入别问我正确性我不会证 我们 ...
随机推荐
- BI怎么选?重点看这10个技术指标
2016年,商业智能市场火热,不管是投资圈还是IT圈,都在广泛关注着大数据和商业智能.宣传广告媒体报道见多了,不知道大家对BI选型的技术标准有谱了没.笔者对Gartner的BI魔力象限考评的15个关键 ...
- [软件逆向]实战Mac系统下的软件分析+Mac QQ和微信的防撤回
0x00 一点废话 最近因为Mac软件收费的比较多,所以买了几款正版软件,但是有的软件卖的有点贵,买了感觉不值,不买吧,又觉得不方便,用别人的吧,又怕不安全.于是我就买了正版的Hopper Di ...
- [20180801]insert导致死锁.txt
[20180801]insert导致死锁.txt --//链接http://www.itpub.net/thread-2104135-2-1.html的讨论,自己有点疏忽了,插入主键相同也会导致死锁. ...
- [20180608]Wrong Results with IOT, Added Column and Secondary Index.txt
[20180608]Wrong Results with IOT, Added Column and Secondary Index.txt --//链接:http://db-oriented.com ...
- python第七十一天---堡垒机
堡垒机的表结构图:
- Xamarin入门,开发一个简单的练手APP
之前周末用Xamarin练手做了个简单APP,没有啥逻辑基本就是个界面架子,MVVM的简单使用,还有Binding,Command的简单使用,还有一个稍微复杂点两个界面交互处理(子页面新增后关闭,父页 ...
- Linux 装机必备工具
linux 装机必备工具:安装这些基本能满足日常需求. #!/usr/bin/env sh echo "Env" # vim # tmux # ssh ...
- python 序列化pickle 和 encode的区别
我们把变量从内存中变成可存储或传输的过程称之为序列化. 序列化之后,就可以把序列化后的内容写入磁盘,或者通过网络传输到别的机器上. 反过来,把变量内容从序列化的对象重新读到内存里称之为反序列化,即un ...
- [SequenceFile_3] MapFile
0. 说明 MapFile 介绍 && 测试 1. 介绍 对 MapFile 的介绍如下: MapFile 是带有索引的 SequenceFile MapFile 是排序的 Seque ...
- 对haproxy文件进行增删改查
1.文件内容 global log 127.0.0.1 local2 daemon maxconn 256 log 127.0.0.1 local2 info defaults log global ...