Description

  

  数轴上有 \(n\)个旗子,第\(i\)个可以插在坐标\(x_i\)或者\(y_i\)。

  

​   请最大化两两旗子之间的最小距离。

  

  ​ \(2 \le n \le 10^4\),\(1 \le x_i,y_i \le 10^9\)

  

  

  

  

  

Solution

  

​   这种有若干组决策,每种决策二选一,然后要求所有决策互相合法的问题,习惯性的要往2-sat想一想。

  

​   我们把每个旗子\(i\)插在\(x_i\)还是\(y_i\)看做一种决策,分别用两个点表示。

  

​   看起来二分答案比较靠谱。

  

​   问题转变为:判定是否存在一种方案,使得两两旗子之间的最小距离不小于\(len\)。

  

​   有了\(x\),我们就很方便地进行逻辑连边了。

  

​   考虑每个旗子\(i\)的两个位置。如果该旗子选择了\(x_i\),则对于所有处于\((x_i-len,x_i+len)\)的位置(除了\(x_i\)),它们对应的旗子在决策时必须选择另一个可选位置,它们必须选择另外一个可选位置\(p\)。因此,从\(x\)向所有的\(p\)连一条边。

  

​   如果该旗子选择了\(y_i\)同理。

  

​   之后进行2-sat,即用Tarjan缩点。如果一个旗子的两个位置处于同一个强联通分量,则无解。否则一定可以构造出一种方案,由于这是一个判定问题,我们不需要真正构造。

  

​   由于点数较大无法\(\mathcal O(n^2)\)连边,我们使用线段树进行连边优化。

  

​   总时间复杂度为\(\mathcal O(n \log_2 n \log_2 1e9)\)

  

Code

  

#include <cstdio>
#include <vector>
#include <algorithm>
#include <unordered_map>
#define pb push_back
using namespace std;
const int N=10005,NUM=N*6;
int n,p[N][2];
int dcnt,d[N*2];
unordered_map<int,int> tid;
int lis[N*2];
int nn;
int dfntm,dfn[NUM],low[NUM],sta[NUM],top,bl[NUM],blcnt;
bool ins[NUM];
int h[NUM],tot;
struct Edge{int v,next;}e[N*100];
inline void addEdge(int u,int v){
//printf("%d %d\n",u,v);
e[++tot]=(Edge){v,h[u]}; h[u]=tot;
}
void readData(){
scanf("%d",&n);
for(int i=1;i<=n;i++)
scanf("%d%d",&p[i][0],&p[i][1]);
}
void Diz(){
for(int i=1;i<=n;i++)
d[++dcnt]=p[i][0], d[++dcnt]=p[i][1];
sort(d+1,d+1+dcnt);
for(int i=1;i<=dcnt;i++)
if(d[i]!=d[i-1]) tid[d[i]]=i;
for(int i=1;i<=n;i++){
int x=p[i][0];
p[i][0]=tid[p[i][0]];
tid[x]++;
x=p[i][1];
p[i][1]=tid[p[i][1]];
tid[x]++;
lis[p[i][0]]=n+i;
lis[p[i][1]]=i;
}
}
namespace SEG{
const int S=N*4;
int rt,sz;
int ch[S][2];
void reset(){
rt=sz=0;
}
void build(int &u,int l,int r){
if(l==r){
u=lis[l];
return;
}
u=++sz;
int mid=(l+r)>>1;
build(ch[u][0],l,mid);
build(ch[u][1],mid+1,r);
addEdge(u,ch[u][0]);
addEdge(u,ch[u][1]);
}
void link(int u,int l,int r,int L,int R,int v){
if(L<=l&&r<=R){
addEdge(v,u);
return;
}
int mid=(l+r)>>1;
if(R<=mid) link(ch[u][0],l,mid,L,R,v);
else if(mid<L) link(ch[u][1],mid+1,r,L,R,v);
else{
link(ch[u][0],l,mid,L,mid,v);
link(ch[u][1],mid+1,r,mid+1,R,v);
}
}
}
void reset(){//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
tot=0;
dfntm=blcnt=0; top=0;
for(int i=1;i<=nn;i++){
h[i]=0;
dfn[i]=low[i]=bl[i]=0;
}
SEG::reset();
}
void tarjan(int u){/*{{{*/
dfn[u]=low[u]=++dfntm;
sta[++top]=u;
ins[u]=true;
for(int i=h[u],v;i;i=e[i].next){
v=e[i].v;
if(!dfn[v]){
tarjan(v);
low[u]=min(low[u],low[v]);
}
else if(ins[v])
low[u]=min(low[u],dfn[v]);
}
if(dfn[u]==low[u]){
blcnt++;
int x;
do{
x=sta[top];
sta[top--]=0;
ins[x]=false;
bl[x]=blcnt;
}while(x!=u);
}
}/*}}}*/
bool judge(int x){
reset();
SEG::sz=n*2;
SEG::build(SEG::rt,1,dcnt);
for(int i=1;i<=n;i++){
int l=lower_bound(d+1,d+1+dcnt,d[p[i][0]]-x+1)-d;
int r=upper_bound(d+1,d+1+dcnt,d[p[i][0]]+x-1)-d-1;
if(l<=r){
if(l<p[i][0])
SEG::link(SEG::rt,1,dcnt,l,p[i][0]-1,i);
if(p[i][0]<r)
SEG::link(SEG::rt,1,dcnt,p[i][0]+1,r,i);
}
l=lower_bound(d+1,d+1+dcnt,d[p[i][1]]-x+1)-d;
r=upper_bound(d+1,d+1+dcnt,d[p[i][1]]+x-1)-d-1;
if(l<=r){
if(l<p[i][1])
SEG::link(SEG::rt,1,dcnt,l,p[i][1]-1,n+i);
if(p[i][1]<r)
SEG::link(SEG::rt,1,dcnt,p[i][1]+1,r,n+i);
}
}
nn=SEG::sz;
for(int i=1;i<=nn;i++)
if(!dfn[i])
tarjan(i);
for(int i=1;i<=n;i++)
if(bl[i]==bl[n+i]) return false;
return true;
}
void solve(){
int l=0,r=1e9,mid;
while(l<=r){
mid=(l+r)>>1;
if(judge(mid))
l=mid+1;
else r=mid-1;
}
printf("%d\n",r);
}
int main(){
readData();
Diz();
solve();
return 0;
}

【ARC069F】Flags的更多相关文章

  1. 【ARC069F】Flags 2-sat+线段树优化建图+二分

    Description ​ 数轴上有 n 个旗子,第 ii 个可以插在坐标 xi或者 yi,最大化两两旗子之间的最小距离. Input ​ 第一行一个整数 N. ​ 接下来 N 行每行两个整数 xi, ...

  2. 【转】Android总结篇系列:Activity Intent Flags及Task相关属性

    [转]Android总结篇系列:Activity Intent Flags及Task相关属性 同上文一样,本文主要引用自网上现有博文,并加上一些自己的理解,在此感谢原作者. 原文地址: http:// ...

  3. Python高手之路【六】python基础之字符串格式化

    Python的字符串格式化有两种方式: 百分号方式.format方式 百分号的方式相对来说比较老,而format方式则是比较先进的方式,企图替换古老的方式,目前两者并存.[PEP-3101] This ...

  4. 【原】FMDB源码阅读(三)

    [原]FMDB源码阅读(三) 本文转载请注明出处 —— polobymulberry-博客园 1. 前言 FMDB比较优秀的地方就在于对多线程的处理.所以这一篇主要是研究FMDB的多线程处理的实现.而 ...

  5. 【原】FMDB源码阅读(二)

    [原]FMDB源码阅读(二) 本文转载请注明出处 -- polobymulberry-博客园 1. 前言 上一篇只是简单地过了一下FMDB一个简单例子的基本流程,并没有涉及到FMDB的所有方方面面,比 ...

  6. 【原】AFNetworking源码阅读(六)

    [原]AFNetworking源码阅读(六) 本文转载请注明出处 —— polobymulberry-博客园 1. 前言 这一篇的想讲的,一个就是分析一下AFSecurityPolicy文件,看看AF ...

  7. 【转】基于linux下的dm9000网卡移植全分析

    转自:http://blog.sina.com.cn/s/blog_6abf2c04010189ui.html DM9000可以直接与ISA总线相连,也可以与大多数CPU直接相连.Mini2440采用 ...

  8. 【Android】一种提高Android应用进程存活率新方法

    [Android]一种提高Android应用进程存活率新方法 SkySeraph Jun. 19st 2016 Email:skyseraph00@163.com 更多精彩请直接访问SkySeraph ...

  9. RT-Thread下的串口驱动程序分析【转载】

    编写本文稿的目的,在于通过分析stm32平台上的串口中断源码,学习 RTT中如何编写中断处理程序 如何编写RTT设备驱动接口代码 了解串行设备的常见处理机制 先以RTT官方源码中的STM32 BSP包 ...

随机推荐

  1. linux/Ubuntu系统上安装mysql数据库(附图详解)

    在前面的文章中,我已经分享了如何在Ubuntu系统中安装以及搭建java开发环境,那么当我们需要跟数据打交道的时候,那么就需要在ubuntu系统中安装一个数据库了,那么废话就不多说了,我们这里主要是分 ...

  2. AssetBundle压缩/内部结构/下载和加载

    一.AssetBundle的压缩方式   Unity支持三种AssetBundle打包的压缩方式:LZMA, LZ4, 以及不压缩.    1.LZMA压缩方式  是一种默认的压缩形式,这种标准压缩格 ...

  3. docker入门使用教程

    Docker概念 Docker是开发人员和系统管理员 使用容器开发,部署和运行应用程序的平台.使用Linux容器部署应用程序称为容器化.容器不是新的,但它们用于轻松部署应用程序. 容器化越来越受欢迎, ...

  4. Babel 入门教程

    Babel是一个广泛使用的转码器,可以将ES6代码转为ES5代码,从而在现有环境执行. 这意味着,你可以现在就用 ES6 编写程序,而不用担心现有环境是否支持.下面是一个例子. // 转码前 inpu ...

  5. Linux安装软件包

    今天在坐公交的路上看到一遍文章感觉还不错,先收集了.原文链接 Linux安装软件包

  6. [BUAA软工]第零次博客作业---问题回答

    [BUAA软工]第0次博客作业 项目 内容 这个作业属于哪个课程 北航软工 这个作业的要求在哪里 第0次个人作业 我在这个课程的目标是 学习如何以团队的形式开发软件,提升个人软件开发能力 这个作业在哪 ...

  7. 第一个Sprint冲刺成果

    组长:李咏江,组员:叶煜稳,谢洪跃,周伟雄 进程:第一个算法功能完成

  8. .NET 类库研究必备参考 扣丁格鲁

    .NET 类库的强大让我们很轻松的解决常见问题,作为一个好专研的程序员,为了更上一层楼,研究CLR的基础类库实现是快速稳定的捷径. 一般场景下,采用 Reflector可以反射出.NET 的部分实现出 ...

  9. [转帖]select提高并发,select和poll、epoll的区别(杂)

    同步IO和异步IO,阻塞IO和非阻塞IO分别是什么,到底有什么区别?不同的人在不同的上下文下给出的答案是不同的.所以先限定一下本文的上下文. https://www.2cto.com/kf/20161 ...

  10. IPV6的链路本地地址和站点本地地址的不同

    转帖 中关村 http://ask.zol.com.cn/x/2230274.html IPV6涉及到一个概念,link-local address, 中文叫“链路本地地址”,它的前缀是FE80::/ ...