题面

传送门: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. Centos-重定向方式打包、备份、还原、恢复工具-cpio

    cpio 通过重定向方式将文件进行打包.备份.还原.恢复工具,扩展名为 .cpio 相关选项 -o 将文件复制.打包成文件或将将文件输出到标准输出 -i  将打包文件或者将设备上的备份还原到系统中 - ...

  2. Spring AOP系列(五)—反射

    前言 前面我们进行了代理模式.静态代理.动态代理的学习.而动态代理就是利用Java的反射技术(Java Reflection),在运行时创建一个实现某些给定接口的新类(也称"动态代理类&qu ...

  3. 模式串 从 0 开始的KMP算法

    /** * 看了 b站视频 BV1jb411V78H 对KMP有了一点理解,然后我写了这个代码 * 这个代码和视频里面的有一点不同,字符串是从 0 开始的,而不是从1 开始的 * 希望能够帮到学习KM ...

  4. Python导入模块的几种方法

    Python 模块 Python 模块(Module),是一个 Python 文件,以 .py 结尾,包含了 Python 对象定义和Python语句. 模块让你能够有逻辑地组织你的 Python 代 ...

  5. matlab receive License Manager Error -103?

    参考:https://www.mathworks.com/matlabcentral/answers/91874-why-do-i-receive-license-manager-error-103 ...

  6. Microsoft.VisualBasic.dll内置的判断变量类型的一系列实用方法

    今天意外读到一线码农的一篇文章<挖一挖C#中那些我们不常用的东西之系列(2)--IsXXX 系列方法>,文章中讲到 Microsoft.VisualBasic.dll 里面的Informa ...

  7. springCloud微服务调用失败【CannotGetJdbcConnectionException: Failed to obtain JDBC Connection】

    详情如下: 2019-07-28 10:56:18.229 ERROR 16212 --- [nio-8081-exec-1] o.a.c.c.C.[.[.[/].[dispatcherServlet ...

  8. 多测师讲解 _接口自动化框架设计_高级讲师肖sir

    背景:因为把传入接口参数.组建测试用例.执行测试用例和发送报告,都放入一个.py文件对于接口的使用非常不灵活就需要数据和接口业务进行分离让代码之间的 耦合性降低.和实现接口的分层管理,所以需要对代码进 ...

  9. 多测师讲解第一个月 _综合面试题_高级讲师肖sir

    第一个月综合面试题 1.  冒烟测试是什么意思?  对主要的用例测试 2.你们公司的项目流程是什么? 3.你们公司的bug分几个级别?  4个 4.你对外键是怎么理解的? 你会使用外键吗?给一个表添加 ...

  10. openstack 高可用环境部署(8节点)(一)