欢迎访问~原文出处——博客园-zhouzhendong

去博客园看该题解


题目传送门 - BZOJ1178


题意概括

  一堆线段,现在取出最多条数,使其互不覆盖,并输出字典序最小的方案。


题解

  这题好坑。

  首先,注意一点,最后不能有多余的空格。

  第一问就是基础的线段覆盖。

  关键在于第二问。

  我们要准备一个函数—— Get_Ans(L,R),用来求解L~R这个区间内,最多可以取多少线段。

  这个可以O(log n)解决。前提是倍增预处理。

  然后就是关键部分。

  我们按照字典序从小到大,能选择就选择。

  怎么判断是否可以选择?只需要在之前选择的线段空隙中可以放这个线段,并且满足Get_Ans(这个线段到它左边的第一条线段之前)+Get_Ans(它到它右边的第一个线段之前)+1 = Get_Ans(他左右两端的),那么就可以放进去。


代码

#include <cstring>
#include <algorithm>
#include <cstdio>
#include <cmath>
#include <cstdlib>
#include <set>
using namespace std;
const int N=200000+5,Inf=1e9;
struct seg{
int L,R;
bool operator < (const seg x) const {
if (L==x.L)
return R>x.R;
return L<x.L;
}
}s[N],s2[N];
int n,rn,Hash[N*2],hs,p[N][20],L[N];
bool alive[N],vis[N*2];
set <int> S;
void HASH(){
sort(Hash+1,Hash+hs+1);
int hs_=1;
for (int i=2;i<=hs;i++)
if (Hash[i]!=Hash[i-1])
Hash[++hs_]=Hash[i];
hs=hs_;
}
void Delete(){
for (int i=1;i<=n;i++)
s2[i]=s[i];
sort(s+1,s+n+1);
memset(alive,true,sizeof alive);
int MinR=Inf,n_=0;
for (int i=n;i>=1;i--)
if (MinR>s[i].R)
MinR=s[i].R;
else
alive[i]=0;
for (int i=1;i<=n;i++)
if (alive[i])
s[++n_]=s[i];
n=n_;
}
void Get_Pos(){
memset(p,0,sizeof p);
for (int i=1;i<=n;i++)
L[i]=s[i].L;
L[n+1]=Inf;
for (int i=1;i<=n;i++){
p[i][0]=upper_bound(L+1,L+n+2,s[i].R)-L;
if (p[i][0]==n+1)
p[i][0]=0;
}
for (int i=1;i<=18;i++)
for (int j=1;j<=n;j++)
p[j][i]=p[p[j][i-1]][i-1];
}
int Get_Ans(int Le,int Ri){
if (Le>Ri||Le>hs)
return 0;
int ans=1,pos=lower_bound(L+1,L+n+2,Le)-L;
if (pos>n||Ri<s[pos].R)
return 0;
for (int i=18;i>=0;i--){
if (!p[pos][i]||s[p[pos][i]].R>Ri)
continue;
pos=p[pos][i];
ans+=1<<i;
}
return ans;
}
int main(){
scanf("%d",&n),rn=n;
for (int i=1;i<=n;i++){
scanf("%d%d",&s[i].L,&s[i].R);
Hash[++hs]=s[i].L;
Hash[++hs]=s[i].R;
}
HASH();
for (int i=1;i<=n;i++){
s[i].L=lower_bound(Hash+1,Hash+hs+1,s[i].L)-Hash;
s[i].R=lower_bound(Hash+1,Hash+hs+1,s[i].R)-Hash;
}
Delete();
Get_Pos();
printf("%d\n",Get_Ans(1,hs));
S.clear();
S.insert(Inf),S.insert(-Inf);
bool empty_block=0;
for (int i=1;i<=rn;i++){
int now=*S.lower_bound(s2[i].L);
if (now==Inf||!vis[now]){
if (now<=s2[i].R)
continue;
int left=*--S.lower_bound(s2[i].L);
int right=*S.lower_bound(s2[i].R);
int val=Get_Ans(left+1,s2[i].L-1)+1+Get_Ans(s2[i].R+1,right-1);
if (val<Get_Ans(left+1,right-1))
continue;
S.insert(s2[i].L);
S.insert(s2[i].R);
if (s2[i].L!=s2[i].R)
vis[s2[i].R]=1;
if (empty_block)
putchar(' ');
printf("%d",i);
empty_block=1;
}
}
return 0;
}

  

BZOJ1178 [Apio2009]CONVENTION会议中心 贪心 set的更多相关文章

  1. bzoj1178 [Apio2009]CONVENTION会议中心 区间dp+贪心

    [Apio2009]CONVENTION会议中心 Time Limit: 15 Sec  Memory Limit: 162 MBSubmit: 1130  Solved: 444[Submit][S ...

  2. BZOJ1178 [Apio2009]CONVENTION会议中心

    本文作者:ljh2000作者博客:http://www.cnblogs.com/ljh2000-jump/转载请注明出处,侵权必究,保留最终解释权! Description Siruseri政府建造了 ...

  3. 【BZOJ-1178】CONVENTION会议中心 倍增 + set (神思路好题!)

    1178: [Apio2009]CONVENTION会议中心 Time Limit: 15 Sec  Memory Limit: 162 MBSubmit: 812  Solved: 323[Subm ...

  4. 1178: [Apio2009]CONVENTION会议中心

    1178: [Apio2009]CONVENTION会议中心 https://lydsy.com/JudgeOnline/problem.php?id=1178 分析: set+倍增. 首先把所有有包 ...

  5. 【bzoj1178】 Apio2009—CONVENTION会议中心

    http://www.lydsy.com/JudgeOnline/problem.php?id=1178 (题目链接) 题意 给出n个区间,问在区间两两不相交的情况下最多能选出多少区间,并输出字典序最 ...

  6. bzoj 1178: [Apio2009]CONVENTION会议中心(少见做法掉落!)【贪心+二分】

    数组若干+手动二分一个的算法,bzoj rank8 ===============================废话分割线=================================== 我我 ...

  7. bzoj 1178 [Apio2009]CONVENTION会议中心

    这题好难啊! 我好菜啊! 思路:对于最多线段不相交, 我们可以按左端点sort之后,贪心取. 但是这个题要求选取的线段排序之后序号的字典序最小. 那么我们如果按序号贪心地从大往小往里放, 那么对于第k ...

  8. 【BZOJ】【1178】【APIO2009】convention会议中心

    贪心 如果不考虑字典序的话,直接按右端点排序,能选就选,就可以算出ans…… 但是要算一个字典序最小的解就比较蛋疼了= = Orz了zyf的题解 就是按字典序从小到大依次枚举,在不改变答案的情况下,能 ...

  9. BZOJ1178 APIO2009 会议中心 贪心、倍增

    传送门 只有第一问就比较水了 每一次贪心地选择当前可以选择的所有线段中右端点最短的,排序之后扫一遍即可. 考虑第二问.按照编号从小到大考虑每一条线段是否能够被加入.假设当前选了一个区间集合\(T\), ...

随机推荐

  1. C# PointToScreen

    子窗体定位时,如果主窗口不在左上角,需要根据主窗口的坐标,相减才行. Point p1 = Label.PointToScreen(new Point(0, 0)); p1.X -= this.X; ...

  2. WPS, 破解WPA/WPA2密钥的捷径

    1.关于WPS(WIFI保护设置) WPS(WIFI保护设置)主要致力于简化无线网络的安全加密设置. 传统方式下,用户新建一个无线网络时,必须在接入点手动设置网络名(SSID)和安全密钥,然后在客户端 ...

  3. Java——关于num++和++num

    public class num_add_add { public static void numAdd(){ int num = 10; int a = num++; System.out.prin ...

  4. [C++]Linux之间隔时间内循环执行指定程序

    #include<time.h> #include<unistd.h>//usleep(num) #include<stdio.h> #include<std ...

  5. 洛谷 P2257 YY的GCD

    洛谷 P2257 YY的GCD \(solution:\) 这道题完全跟[POI2007]ZAP-Queries (莫比乌斯反演+整除分块) 用的一个套路. 我们可以列出答案就是要我们求: \(ans ...

  6. JQuery 的Bind()事件

    刚开始我们先看一下它的定义: .bind( eventType [, eventData], handler(eventObject)) .Bind()方法的主要功能是在向它绑定的对象上面提供一些事件 ...

  7. js常用的工具函数

    JS选取DOM元素的方法注意:原生JS选取DOM元素比使用jQuery类库选取要快很多1.通过ID选取元素document.getElementById('myid');2.通过CLASS选取元素do ...

  8. jquery筛选数组之grep、each、inArray、map的用法及遍历son对象(转)

    grep [传入的参数为返回bool类型的函数] <script type='text/javascript' src="/jquery.js"></script ...

  9. unicode 和 utf-8字符编码的区别

    作者:于洋链接:https://www.zhihu.com/question/23374078/answer/69732605来源:知乎著作权归作者所有,转载请联系作者获得授权.   原文:unico ...

  10. HTML学习笔记01-HTML简介

    主要是为了做接口测试,试着自己写爬虫,所以学习一下HTML一些基础的东西,方便用来解析网页.学习内容主要来自菜鸟教程的HTML教程,W3school的HTML 超文本标记语言(英语:HyperText ...