题面

传送门:https://www.luogu.org/problemnew/show/P3626


Solution

如果题目只要求求出第一问,那这题显然就是大水题。

但是加上第二问的话.......那这题就成为大(du)火(liu)题了。

对于第一问:求一整个区间的最大线段总数,我们可以很轻松的切掉。

怎么处理第二问呢?

我们可以考虑这样做:

对于一条线段,如果它属于答案的一部分,那么它一定会有以下性质:

区间③的最大线段数 = 区间①的最大线段数 + 区间②的最大线段数 + 1(当前线段) (区间最大线段数指用传统贪心方法求出的一段区间的可能的最多的线段的数量)

那怎么求一段区间的最大线段数呢?

第一想法是前缀和?看起来很OK?

nope

因为不同区间中,里面的的初始线段会不同,以下这个图可以简单说明这种情况

但是,我们可以发现一个很重要的特点:

每条线段的下一条可行线段是固定的

有了这个特点,我们就可以对路径做倍增,就可以在log的时间求出某一个区间的线段数。

至于求每一个区间的第一条线段,我们可以用set+lowbound的方法找。

这样子,你就可以嘴巴AC这道题啦

实际上你会花费大量的时间来调这道毒瘤题


(我常数太大,开O2才能卡过(set太辣鸡))

Code

// luogu-judger-enable-o2
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<set>
#include<stack>
#include<cstring>
#include<vector>
using namespace std;
long long read()
{
long long x=0,f=1; char c=getchar();
while(!isdigit(c)){if(c=='-') f=-1;c=getchar();}
while(isdigit(c)){x=x*10+c-'0';c=getchar();}
return x*f;
}
const int N=200000+100;
struct line
{
int l,r,no;
friend bool operator < (line A,line B)
{
return A.l<B.l;
}
}l[N];
bool cmp(line A,line B)
{
if(A.l==B.l)
{
if(A.r!=B.r)
return A.r>B.r;
else
return A.no>B.no;
}
return A.l<B.l;
}
bool cmp2(line A,line B)
{
return A.no<B.no;
}
int n,ans,root,fa[N][20+2];
bool use[N],vis[N];
stack <int> ms;
set <line> mset;
set <line> used;
vector <int> e[N];
void dfs(int now,int FA)
{
vis[now]=true;
fa[now][0]=FA;
for(int i=1;i<=20;i++)
fa[now][i]=fa[fa[now][i-1]][i-1];
for(int i=0;i<int(e[now].size());i++)
if(vis[e[now][i]]==false)
dfs(e[now][i],now);
}
int POW[21];
int Count(int L,int R)
{
line temp; temp.l=L;
set<line>:: iterator t=mset.lower_bound(temp);
if((*t).r > R) return 0;
int now=(*t).no,ans=1;
for(int i=20;i>=0;i--)
if(l[fa[now][i]].r<=R and fa[now][i]!=0)
now=fa[now][i],ans+=POW[i];
return ans;
}
int main()
{
//freopen("center.in","r",stdin);
//freopen("center.out","w",stdout); n=read();
for(int i=1;i<=n;i++)
l[i].l=read(),l[i].r=read(),l[i].no=i; sort(l+1,l+1+n,cmp);
memset(use,1,sizeof use);
for(int i=1;i<=n;i++)
{
while(ms.empty()==false and l[ms.top()].r>=l[i].r)
{
use[ms.top()]=false;
ms.pop();
}
ms.push(i);
}
int to=-1;
for(int i=1;i<=n;i++)
if(use[i]==true and l[i].l>to)
{
ans++;
to=l[i].r;
}
for(int i=1;i<=n;i++) e[i].reserve(4);
for(int i=1;i<=n;i++)
if(use[i]==true)
{
//cerr<<l[i].no<<" ";
mset.insert(l[i]);
bool OK=false;
for(int j=i+1;j<=n;j++)
if(use[j]==true and l[j].l>l[i].r)
{
e[l[j].no].push_back(l[i].no);
OK=true;
break;
}
if(OK==false)
e[0].push_back(l[i].no);
}
printf("%d\n",ans); dfs(0,0);
sort(l+1,l+1+n,cmp2);
for(int i=0;i<=20;i++)
POW[i]=1<<i;
l[0].r=0x3f3f3f3f;
line tt;
tt.l=-1,tt.r=-1,tt.no=0; mset.insert(tt),used.insert(tt);
tt.l=0x3f3f3f3f,tt.r=0x3f3f3f3f;mset.insert(tt),used.insert(tt);
for(int i=1;i<=n;i++)
{
int L,R;
set<line>:: iterator t=used.lower_bound(l[i]);
if((*t).l<=l[i].r) continue;
R=(*t).l-1;
t--;
if((*t).r>=l[i].l) continue;
L=(*t).r+1;
if(Count(L,l[i].l-1)+Count(l[i].r+1,R)==Count(L,R)-1)
{
printf("%d ",i);
used.insert(l[i]);
}
}
return 0;
}

[Luogu P3626] [APIO2009] 会议中心的更多相关文章

  1. Luogu 3626 [APIO2009]会议中心

    很优美的解法. 推荐大佬博客 如果没有保证字典序最小这一个要求,这题就是一个水题了,但是要保证字典序最小,然后我就不会了…… 如果一条线段能放入一个区间$[l', r']$并且不影响最优答案,那么对于 ...

  2. P3626 [APIO2009]会议中心

    传送门 好迷的思路-- 首先,如果只有第一问就是个贪心,排个序就行了 对于第二问,我们考虑这样的一种构造方式,每一次都判断加入一个区间是否会使答案变差,如果不会的话就将他加入别问我正确性我不会证 我们 ...

  3. 【题解】[APIO2009]会议中心

    [题解][P3626 APIO2009]会议中心 真的是一道好题!!!刷新了我对倍增浅显的认识. 此题若没有第二份输出一个字典序的方案,就是一道\(sort+\)贪心,但是第二问使得我们要用另外的办法 ...

  4. [APIO2009]会议中心(贪心)

    P3626 [APIO2009]会议中心 题目描述 Siruseri 政府建造了一座新的会议中心.许多公司对租借会议中心的会堂很 感兴趣,他们希望能够在里面举行会议. 对于一个客户而言,仅当在开会时能 ...

  5. [APIO2009]会议中心

    [APIO2009]会议中心 题目大意: 原网址与样例戳我! 给定n个区间,询问以下问题: 1.最多能够选择多少个不相交的区间? 2.在第一问的基础上,输出字典序最小的方案. 数据范围:\(n \le ...

  6. BZOJ.1178.[APIO2009]会议中心(贪心 倍增)

    BZOJ 洛谷 \(Description\) 给定\(n\)个区间\([L_i,R_i]\),要选出尽量多的区间,并满足它们互不相交.求最多能选出多少个的区间以及字典序最小的方案. \(n\leq2 ...

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

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

  8. BZOJ1178或洛谷3626 [APIO2009]会议中心

    BZOJ原题链接 洛谷原题链接 第一个问题是经典的最多不相交区间问题,用贪心即可解决. 主要问题是第二个,求最小字典序的方案. 我们可以尝试从\(1\to n\)扫一遍所有区间,按顺序对每一个不会使答 ...

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

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

随机推荐

  1. [vue-webpack-template] webpack配置全局less引入

    1. 项目模板webpack vue init webpack <项目名> 2. 安装依赖 除了less所需的less less-loader两个包以外,还需要安装style-resour ...

  2. 小白也能看懂的Redis教学基础篇——朋友面试被Skiplist跳跃表拦住了

    各位看官大大们,双节快乐 !!! 这是本系列博客的第二篇,主要讲的是Redis基础数据结构中ZSet(有序集合)底层实现之一的Skiplist跳跃表. 不知道那些是Redis基础数据结构的看官们,可以 ...

  3. STM32CubeMX HAL库串口: 使用DMA数据发送、使用DMA不定长度数据接收

    转载自 https://blog.csdn.net/euxnijuoh/article/details/81638676

  4. C++ 关键字 enum

    转自:https://blog.csdn.net/cppwork/article/details/18814315 C++ 关键字 enum. 枚举 1.  概念 我们经常需要为某些属性定义一组可选择 ...

  5. 在Linux下如何根据域名自签发OpenSSL证书与常用证书转换

    在Linux下如何根据域名自签发各种SSL证书,这里我们以Apache.Tomcat.Nginx为例. openssl自签发泛域名(通配符)证书 首先要有openssl工具,如果没有那么使用如下命令安 ...

  6. vscode编写python,引用本地py文件出现红色波浪线

    前言 引用本地py文件出现红色波浪线,如下图: 原因 经过查询得知,vscode中的python插件默认使用的是pylint来做代码检查,因此需要对pylint做一些配置 解决方案 在setting. ...

  7. Oracle误操作 数据恢复

    SELECT * FROM v$sqlarea //查询最近sql记录 SELECT r.FIRST_LOAD_TIME,r.* FROM v$sqlarea r ORDER BY r.FIRST_L ...

  8. 面试题____pthon__002(法本_) 阿里

    1.描述一下您负责的业务中最复杂的业务(可以从业务是为了解决用户的什么问题切入).这个最复杂的业务中,最复杂的模块是什么,这个模块的主要功能详细描述一下.这个模块,采用了什么样的测试手段保障质量?2. ...

  9. docker 升级后或者重装后,启动容器提示:Error response from daemon: Unknown runtime specified docker-runc

    之前安装的版本是docker 1.3,并运行了容器jenkins 现在把docker升级版本为docker-ce 19.03 再使用docker ps发现之前的jenkins容器已经退出了 启动容器: ...

  10. Mock测试你的Spring MVC接口

    1. 前言 在Java开发中接触的开发者大多数不太注重对接口的测试,结果在联调对接中出现各种问题.也有的使用Postman等工具进行测试,虽然在使用上没有什么问题,如果接口增加了权限测试起来就比较恶心 ...