[APIO2009]会议中心
[APIO2009]会议中心
题目大意:
原网址与样例戳我!
给定n个区间,询问以下问题:
- 1.最多能够选择多少个不相交的区间?
- 2.在第一问的基础上,输出字典序最小的方案。
数据范围:\(n \leq 2\times 10^5\)
前言:几个小 \(tips\)
对于字典序最小的构造题,一个套路:
以字典序从小到大枚举,依次检查每个元素是否可以计入答案。
然后是两个函数的辨析:
\(lower\_ bound(x)\):返还第一个大于等于\((\ge)\)\(x\)的位置。
\(upper\_bound(x)\):返还第一个严格大于\((>)\)\(x\)的位置。
正文:解法与思路
\(Tag\):贪心 + 倍增 + \(set\)
A
先去掉包含关系,原因略,此时左右端点都是递增的了。
第一问简直弱智,贪心的入门题,这里不说了,关键在于字典序最小方案如何输出。
考虑上文中说到的那个套路:
以字典序从小到大枚举每一条线段,判断加入这条区间后答案是否会变差。
如果答案不会变差,那么肯定就优先选择这个区间了。
下面我们来看如何判断加入区间后答案是否变差。
B
我们令\(f(lp,rp)\)表示在\([lp,rp]\)这个区间内最多可以选择的区间个数。
那么,假设我们把区间\([l_0,r_0]\)插入,
如果答案不会变差,对于所有的区间\([lp',rp']\),应该都有:
\[f(lp',rp') = f(lp',l_0-1) + f(r_0+1,rp') + 1\]
自己yy一下即可。
显然,加入区间\([l_0,r_0]\)的影响范围是有限的,我们可以发现这个范围为:
左边界 \(lp\):已经加入的区间中,在\([l_0,r_0]\)的左边的那个区间的右端点。
右边界 \(rp\):已经加入的区间中,在\([l_0,r_0]\)的右边的那个区间的左端点。
C
由上文可知,我们枚举区间,每次得到\(lp\ ,\ rp\),然后需要判断上面的等式是否成立。
如果成立,则把此区间加入答案集合中,否则\(continue\)。
给定\(lp\ ,\ rp\) , 如何快速求\(f(lp,rp)\)呢? 考虑倍增。
把原区间序列按左端点排序,得到一个新区间序列,
令\(nxt[x][d]\) 表示从第\(x\)个区间向后选择\(2^d\)个区间(不包括\(x\)),最后一个区间为\(nxt[x][d]\)。
转移显然:\(nxt[x][d] = nxt[\ nxt[x][d-1]\ ][d-1]\)。
有了\(nxt\)数组后,每次给定\(lp\ ,\ rp\),先二分找到范围内第一个区间,然后倍增求解即可。
D
大体思路就这样,本题的实现上也有一定的难度。
听说可以用线段树或\(splay\) , 反正我使用的是\(set\)来求解。
在从前往后扫的过程中,我们用\(set\)来保存已经加入答案的区间集合。
\(set\)中的区间以右端点为优先级排序,每次找影响范围\(l\ ,\ r\)直接在\(set\)里二分即可。
然后注意得到\(lp\ ,\ rp\)后要判交,如果交了也要\(continue\)。
细节上,计算\(f(lp,rp)\)的时候注意判断答案为0的情况,\(nxt[i][0]\)也可以二分求解。
实现代码:
注:\(q[i]\)为题目给定的原区间序列 , \(t[i]\)为去重、以左端点排序后的新区间序列。
#include<bits/stdc++.h>
#define RG register
#define IL inline
#define inf 1e9+7
#define _ 200005
using namespace std;
int xx[3*_] , f[_][20] ,N,n,m,tot1,tot,lp,rp,s1,s2;
int Ans ; queue< int > ans ;
struct node{
int l , r ;
IL bool operator < (const node &B)const{ return r < B.r ; }
};
node t[_] , q[_] ; set< node > S ; set< node >::iterator t1 ,t2 ;
IL bool cmp(node a , node b){return (a.l==b.l)?a.r>b.r : a.l<b.l ;}
IL void Prepare(){;
for(RG int i = 1; i <= n; i ++) xx[ i ] = t[ i ].l ;
xx[ n + 1 ] = inf ; tot1 = n + 1;
for(RG int i = 1; i <= n; i ++)
f[ i ][ 0 ] = upper_bound(xx+1,xx+tot1+1,t[ i ].r) - xx ;
for(RG int i = 1; i <= n; i ++)
if(f[ i ][ 0 ] == n + 1)f[ i ][ 0 ] = 0 ;
for(RG int j = 1; j <= 19 ; j ++)
for(RG int i = 1; i <= n; i ++)
f[ i ][ j ] = f[ f[ i ][ j - 1 ] ][ j - 1 ] ;
return ;
}//f[i][j] 表示从i开始(不算i)向后选择2^j个区间,最后一个为第f[i][j]个区间.
IL void Pre(){
cin >> n ; N = n ; tot1 = 0 ; tot = 0;
for(RG int i = 1,l,r; i <= n; i ++) cin >> q[i].l >> q[i].r ;
for(RG int i = 1; i <= n; i ++)
t[ i ].l = q[ i ].l , t[ i ].r = q[ i ].r;
sort(t + 1 , t + n + 1 , cmp ) ; t[ ++ tot ] = t[ 1 ] ;
for(RG int i = 2; i <= n; i ++){
while(t[ i ].r <= t[ tot ].r && tot) -- tot ;
t[ ++ tot ] = t[ i ] ;
}// 去重
n = tot ; Prepare() ;
}
IL int Calc(RG int L , RG int R){
RG int c = lower_bound(xx + 1, xx + n + 1 , L) - xx;
if(R < L || t[c].r > R || c > n) return 0 ;
RG int res = 0;
for(RG int i = 19; i >= 0 ; i --)
if(f[ c ][ i ] && t[ f[ c ][ i ] ].r <= R)
c = f[ c ][ i ] , res |= (1 << i) ;
return res + 1 ; //记得加上范围内的第一个区间
}
int main(){
std::ios::sync_with_stdio(false) ;
Pre() ;
S.insert( (node){-inf , -inf} ) ;
S.insert( (node){inf , inf} ) ;
Ans = Calc(-inf , inf) ;
for(RG int i = 1; i <= N; i ++){
t2 = S.lower_bound( q[ i ] ) ; t1 = t2 ; t1 -- ;
lp = (*t1).r ; rp = (*t2).l ;
if(lp >= q[i].l || rp <= q[i].r) continue ; //判交
lp ++ ; rp -- ;
s1 = Calc(lp , q[i].l - 1) + Calc(q[i].r + 1 , rp) + 1;
s2 = Calc(lp , rp) ;
if( ! (s1 ^ s2) )
ans.push( i ) , S.insert( q[ i ] ) ;
}
cout << Ans << endl;
while(!ans.empty())printf("%d ",ans.front()) , ans.pop() ;
return 0;
}
[APIO2009]会议中心的更多相关文章
- 【题解】[APIO2009]会议中心
[题解][P3626 APIO2009]会议中心 真的是一道好题!!!刷新了我对倍增浅显的认识. 此题若没有第二份输出一个字典序的方案,就是一道\(sort+\)贪心,但是第二问使得我们要用另外的办法 ...
- [APIO2009]会议中心(贪心)
P3626 [APIO2009]会议中心 题目描述 Siruseri 政府建造了一座新的会议中心.许多公司对租借会议中心的会堂很 感兴趣,他们希望能够在里面举行会议. 对于一个客户而言,仅当在开会时能 ...
- BZOJ.1178.[APIO2009]会议中心(贪心 倍增)
BZOJ 洛谷 \(Description\) 给定\(n\)个区间\([L_i,R_i]\),要选出尽量多的区间,并满足它们互不相交.求最多能选出多少个的区间以及字典序最小的方案. \(n\leq2 ...
- BZOJ1178 APIO2009 会议中心 贪心、倍增
传送门 只有第一问就比较水了 每一次贪心地选择当前可以选择的所有线段中右端点最短的,排序之后扫一遍即可. 考虑第二问.按照编号从小到大考虑每一条线段是否能够被加入.假设当前选了一个区间集合\(T\), ...
- BZOJ1178或洛谷3626 [APIO2009]会议中心
BZOJ原题链接 洛谷原题链接 第一个问题是经典的最多不相交区间问题,用贪心即可解决. 主要问题是第二个,求最小字典序的方案. 我们可以尝试从\(1\to n\)扫一遍所有区间,按顺序对每一个不会使答 ...
- Luogu 3626 [APIO2009]会议中心
很优美的解法. 推荐大佬博客 如果没有保证字典序最小这一个要求,这题就是一个水题了,但是要保证字典序最小,然后我就不会了…… 如果一条线段能放入一个区间$[l', r']$并且不影响最优答案,那么对于 ...
- P3626 [APIO2009]会议中心
传送门 好迷的思路-- 首先,如果只有第一问就是个贪心,排个序就行了 对于第二问,我们考虑这样的一种构造方式,每一次都判断加入一个区间是否会使答案变差,如果不会的话就将他加入别问我正确性我不会证 我们 ...
- [Luogu P3626] [APIO2009] 会议中心
题面 传送门:https://www.luogu.org/problemnew/show/P3626 Solution 如果题目只要求求出第一问,那这题显然就是大水题. 但是加上第二问的话...... ...
- 【BZOJ】【1178】【APIO2009】convention会议中心
贪心 如果不考虑字典序的话,直接按右端点排序,能选就选,就可以算出ans…… 但是要算一个字典序最小的解就比较蛋疼了= = Orz了zyf的题解 就是按字典序从小到大依次枚举,在不改变答案的情况下,能 ...
随机推荐
- 菜鸟的it之路-起航
之前在知乎上看见怎么学习数据结构下一位答主的回答,他引用了N.Wirth(沃斯)的话:程序=数据结构+算法.(哈,菜鸟无法验证这句话的正确性有多大)但毫无疑问的是,数据结构应当是一名菜鸟程序狗要重点学 ...
- 一步一步从原理跟我学邮件收取及发送 13.mime格式与常见字符编码
在前面的本系列文章中我们已经学会了邮件的发送和收取.但在收取中我们看到的是一串串的乱码,回忆前面的发送过程,我们会奇怪:我们前面的邮件是明文啊.为什么明文的邮件明明也可以正常工作,还要弄乱码似的字符串 ...
- 从flexible.js引入高德地图谈起的移动端适配
曾几何时,前端还仅仅是PC端的.随着移动时代的兴起,h5及css3的推陈出新.前端的领域慢慢的由传统的pc端转入了移动端,这也导致了前端这一职业在风口的一段时间出尽了风头. 从开始的惶恐和无从下手,慢 ...
- ch7复用类
导出类的初始化是从基类开始向下扩展的,先初始化基类,再初始化由基类继承而来的类. 若类B需要类A中的一些甚至全部方法,但类B实际上不是并不是真正的类A,则可以通过代理的方式在B中实现所需要的A的方法, ...
- IntentService源码
原文地址IntentService源码分析 @Override public void onCreate() { super.onCreate(); HandlerThread thread = ne ...
- hihoCoder Demo Day dp
题意:有一个机器人被困在一个的迷宫中,机器人的初始位置是,目的地是,并且它的移动方式很奇怪:只能一直向右,直到不能再向右才能把方向变成向下:只能一直向下,直到不能再向下才能把方向变成向右.迷宫中的每个 ...
- tcp/ip 卷一 读书笔记(5)arp和rarp 同网段和不同网段之间的通信过程
arp和rarp 同网段和不同网段之间的通信过程 IPv6中已经没有arp rarp协议,所以这里都是IPv4. 链路层使用以太网地址来确定目的地址,应用则常使用ip地址通信 arp协议是指从ip地址 ...
- 跨域问题jsonp
不得不说的同源政策: 同源策略,它是由Netscape提出的一个著名的安全策略.现在所有支持JavaScript 的浏览器都会使用这个策略.所谓同源是指域名,协议,端口相同.当一个浏览器的两个tab页 ...
- webpack打包速度和性能再次优化
一. 改单dll为双dll 因为上图原因,使用CommonsChunkPlugin时,导致其打包出来的vendors.js内的模块ID会因为其他文件引用模块数量的变化而变化. 所以现利用DllPlug ...
- 【Unity3D】Unity3D开发《我的世界》之四、创建一个Block
转载请注明出处:http://www.cnblogs.com/shamoyuu/p/unity_minecraft_04.html 一.新建Block类 我们的Block类用来存储跟Block相关的信 ...