题面

传送门: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. tornado-简介和原理

    tornado-设计初衷 1. 追求小而精 2. epoll IO多路复用和协程 3. 支持WebSocket 4. 单线程程序(GIL限制,本身某种意义上不启动多进程就是单线程程序) # Pytho ...

  2. spring-boot-route(六)整合JApiDocs生成接口文档

    上一篇文章中介绍了使用Swagger生成接口文档,非常方便,功能也十分强大.如果非要说Swaager有什么缺点,想必就是注解写起来比较麻烦.如果我说有一款不用写注解,就可以生成文档的工具,你心动了吗? ...

  3. Java知识系统回顾整理01基础04操作符02关系操作符

    一.关系操作符 关系操作符:比较两个变量之间的关系  > 大于 >= 大于或等于 < 小于 <= 小于或等于 == 是否相等 != 是否不等 public class Hell ...

  4. 【随笔】菜刀(代码执行)函数和命令执行函数详解及Getshell方法

    代码执行函数 VS 命令执行函数 一直想整理这两块的内容,但是一直没时间弄,直到前两天碰上一个写入了菜刀马但是死活连不上菜刀的站,顿时不知道怎么继续了,所以就趁这个机会整理了一下代码执行函数怎么get ...

  5. Splay浅谈

    Splay是众多平衡树之一,它的功能十分强大,但常数极大.在LCT和许多数据结构中都能用到. Splay的核心操作,就是rotate.为了使树不是一条链,而是平衡的,我们需要旋转来维护形态.理论很简单 ...

  6. SpringBoot-06-模板引擎Thymeleaf

    6. 模板引擎 Thymeleaf Thyme leaf 英译为 百里香的叶子. 模板引擎 ​ 以前开发中使用的jsp就是一个模板引擎,但是springboot 以jar的方式,并且使用嵌入式的tom ...

  7. Mac Idea你不知道的秘密

    导读 工欲善其事必先利其器,日常工作中,知道这些Idea技巧,可以极大提高日常开发效率. 技巧篇 以下内容不分先后顺序 显示类中的方法 搜索 搜索方法,按两下shift 文字搜索,control+sh ...

  8. [WC 2011]最大Xor和路径

    题目大意: 给你一张n个点,m条边的无向图,每条边都有一个权值,求:1到n的路径权值和的最大值. 题解: 任意一条路径都能够由一条简单路径(任意一条),在接上若干个环构成(如果不与这条简单路径相连就走 ...

  9. RHSA-2017:1842-重要: 内核 安全和BUG修复更新(需要重启、存在EXP、本地提权、代码执行)

    [root@localhost ~]# cat /etc/redhat-release CentOS Linux release 7.2.1511 (Core) 修复命令: 使用root账号登陆She ...

  10. java -inally转

    1.不管有木有出现异常,finally块中代码都会执行: 2.当try和catch中有return时,finally仍然会执行:3.finally是在return后面的表达式运算后执行的(此时并没有返 ...