Description

​ 数轴上有 n 个旗子,第 ii 个可以插在坐标 xi或者 yi,最大化两两旗子之间的最小距离。

Input

​ 第一行一个整数 N。

​ 接下来 N 行每行两个整数 xi,yi

Output

​ 一个整数表示答案。

Sample Input

Sample #1
3
1 3
2 5
1 9 Sample #2
5
2 2
2 2
2 2
2 2
2 2 Sample #3
22
93 6440
78 6647
862 11
8306 9689
798 99
801 521
188 206
6079 971
4559 209
50 94
92 6270
5403 560
803 83
1855 99
42 504
75 484
629 11
92 122
3359 37
28 16
648 14
11 269

Sample Output

Sample #1
4 Sample #2
0 Sample #3
17

HINT

​ 2≤N≤10^4

​ 1≤xi,yi≤10^9

Sol

线段树优化建图+2-sat+二分。

首先我们二分答案k,然后把一个点向离他距离为k以内的点的反点连边(2-sat的边表示依赖关系),之后直接判断有没有解,但是显然这样会TLE,因为边的个数是\(n^2\)级别的。

所以考虑线段树优化建图,步骤为:

1.按照2n个点排序,建出线段树,每个点向他的父亲连边,最底层点向这个点代表的点的反点连边(因为2-sat连的是反点,别的题没有必要)

2.对于每个点进行编号(一共2n个)。

3.我们考虑每个点,找到和他距离k以内的点的两段区间,然后用这个点按照线段树区间查找的方式向logn个区间连边。(注意一定要跳过自己对应的点,因为这代表着自己的反点,不能连边)

中间有点细节,要注意一下。

之后就是2-sat的经典应用了。

Code

#include <bits/stdc++.h>
using namespace std;
struct seg{int l,r,id;seg(int l=0,int r=0,int id=0):l(l),r(r),id(id){}}s[500005];
int n,P,Index,L,p[100005][2],dfn[100005],low[100005],in[100005],cnt,bel[100005],b[100005],x[100005],y[100005],X[100005],Y[100005],vis[100005];
pair<int,int>pos[100005];vector<int>e[100005];stack<int>q;
void build(int x,int L,int R)
{
s[x]=seg(L,R,++P);
if(x>>1) e[s[x>>1].id].push_back(s[x].id);
if(L==R){e[s[x].id].push_back(p[pos[L].first][pos[L].second^1]);return;}
int mid=(L+R)>>1;build(x*2,L,mid);build(x*2+1,mid+1,R);
}
void ins(int x,int L,int R,int u)
{
if(L>R) return;
if(s[x].l==L&&s[x].r==R){e[u].push_back(s[x].id);return;}
int mid=(s[x].l+s[x].r)>>1;
if(R<=mid) ins(x*2,L,R,u);else if(L>mid) ins(x*2+1,L,R,u);
else ins(x*2,L,mid,u),ins(x*2+1,mid+1,R,u);
}
void tarjan(int x)
{
dfn[x]=low[x]=++Index;in[x]=1;q.push(x);
for(int i=0;i<e[x].size();i++)
if(!dfn[e[x][i]]) tarjan(e[x][i]),low[x]=min(low[x],low[e[x][i]]);
else if(in[e[x][i]]) low[x]=min(low[x],dfn[e[x][i]]);
if(dfn[x]==low[x]) for(cnt++;;){int now=q.top();q.pop();in[now]=0;bel[now]=cnt;if(now==x) break;}
}
bool chk(int k)
{
P=cnt=Index=0;for(int i=0;i<=n*5;i++) e[i].clear();while(!q.empty()) q.pop();
memset(dfn,0,sizeof(dfn));memset(low,0,sizeof(low));memset(in,0,sizeof(in));memset(bel,0,sizeof(bel));
for(int i=1;i<=n;i++) p[i][0]=++P,p[i][1]=++P;
build(1,1,L);
for(int i=1;i<=n;i++)
ins(1,upper_bound(b+1,b+L+1,X[i]-k)-b,x[i]-1,p[i][0]),ins(1,x[i]+1,lower_bound(b+1,b+L+1,X[i]+k)-b-1,p[i][0]),
ins(1,upper_bound(b+1,b+L+1,Y[i]-k)-b,y[i]-1,p[i][1]),ins(1,y[i]+1,lower_bound(b+1,b+L+1,Y[i]+k)-b-1,p[i][1]);
for(int i=1;i<=P;i++) if(!dfn[i]) tarjan(i);int ok=1;
for(int i=1;i<=n;i++) if(bel[p[i][0]]==bel[p[i][1]]) ok=0;
return ok;
}
int find(int I,int P,int x)
{
int res,l=1,r=L;
for(int mid=(l+r)>>1;l<=r;mid=(l+r)>>1)
{
if(b[mid]==x&&!vis[mid]) res=mid,r=mid-1;
else if(b[mid]>x) r=mid-1;else l=mid+1;
}
vis[res]=1;pos[res]=make_pair(I,P);return res;
}
int main()
{
scanf("%d",&n);int l=0,r=1e9,ans;
for(int i=1;i<=n;i++) scanf("%d%d",&X[i],&Y[i]),b[++L]=X[i],b[++L]=Y[i];
sort(b+1,b+L+1);
for(int i=1;i<=n;i++) x[i]=find(i,0,X[i]),y[i]=find(i,1,Y[i]);
for(int mid=(l+r)>>1;l<=r;mid=(l+r)>>1) if(chk(mid)) l=mid+1,ans=mid;else r=mid-1;
printf("%d\n",ans);
}

【ARC069F】Flags 2-sat+线段树优化建图+二分的更多相关文章

  1. 2-sat 问题 【例题 Flags(2-sat+线段树优化建图)】

    序: 模拟赛考了一道 2-sat 问题.之前从来没听过…… 考完才发现其实这个东东只要一个小小的 tarjan 求强连通分量就搞定了. 这个方法真是巧妙啊,拿来讲讲. What is it? [・_・ ...

  2. BZOJ5017 [SNOI2017]炸弹 - 线段树优化建图+Tarjan

    Solution 一个点向一个区间内的所有点连边, 可以用线段树优化建图来优化 : 前置技能传送门 然后就得到一个有向图, 一个联通块内的炸弹可以互相引爆, 所以进行缩点变成$DAG$ 然后拓扑排序. ...

  3. 【BZOJ3681】Arietta 树链剖分+可持久化线段树优化建图+网络流

    [BZOJ3681]Arietta Description Arietta 的命运与她的妹妹不同,在她的妹妹已经走进学院的时候,她仍然留在山村中.但是她从未停止过和恋人 Velding 的书信往来.一 ...

  4. 【bzoj5017】[Snoi2017]炸弹 线段树优化建图+Tarjan+拓扑排序

    题目描述 在一条直线上有 N 个炸弹,每个炸弹的坐标是 Xi,爆炸半径是 Ri,当一个炸弹爆炸时,如果另一个炸弹所在位置 Xj 满足:  Xi−Ri≤Xj≤Xi+Ri,那么,该炸弹也会被引爆.  现在 ...

  5. 【bzoj4699】树上的最短路(树剖+线段树优化建图)

    题意 给你一棵 $n$ 个点 $n-1$ 条边的树,每条边有一个通过时间.此外有 $m$ 个传送条件 $(x_1,y_1,x_2,y_2,c)$,表示从 $x_1$ 到 $x_2$ 的简单路径上的点可 ...

  6. 【BZOJ4276】[ONTAK2015]Bajtman i Okrągły Robin 线段树优化建图+费用流

    [BZOJ4276][ONTAK2015]Bajtman i Okrągły Robin Description 有n个强盗,其中第i个强盗会在[a[i],a[i]+1],[a[i]+1,a[i]+2 ...

  7. 【bzoj3073】[Pa2011]Journeys 线段树优化建图+堆优化Dijkstra

    题目描述 Seter建造了一个很大的星球,他准备建造N个国家和无数双向道路.N个国家很快建造好了,用1..N编号,但是他发现道路实在太多了,他要一条条建简直是不可能的!于是他以如下方式建造道路:(a, ...

  8. 【bzoj4383】[POI2015]Pustynia 线段树优化建图+差分约束系统+拓扑排序

    题目描述 给定一个长度为n的正整数序列a,每个数都在1到10^9范围内,告诉你其中s个数,并给出m条信息,每条信息包含三个数l,r,k以及接下来k个正整数,表示a[l],a[l+1],...,a[r- ...

  9. BZOJ_4276_[ONTAK2015]Bajtman i Okrągły Robin_线段树优化建图+最大费用最大流

    BZOJ_4276_[ONTAK2015]Bajtman i Okrągły Robin_线段树优化建图+最大费用最大流 Description 有n个强盗,其中第i个强盗会在[a[i],a[i]+1 ...

随机推荐

  1. 数据结构(c语言描述)

    预备的数学知识 数据结构的概念 基本名词 算法 线性表 线性表的定义和基本操作 顺序表 顺序表增 顺序表删 顺序表查 单链表 建立单链表 单链表增 单链表删 单链表查 双链表 循环链表 静态链表 栈 ...

  2. KMP算法详解(转)

    转自http://www.matrix67.com/blog/archives/115 通常我们的方法是枚举从A串的什么位置起开始与B匹配,然后验证是否匹配.假如A串长度为n,B串长度为m,那么这种方 ...

  3. Python 编码机制

    python 编码转换 Python的编码机制,unicode, utf-8, utf-16, GBK, GB2312,ISO-8859-1 等编码之间的转换. 常见的编码转换分为以下几种情况: 自动 ...

  4. 十分钟学会Fiddler

    一.Fiddler介绍 Fiddler是一个http抓包改包工具,fiddle英文中有“欺骗.伪造”之意,与wireshark相比它更轻量级,上手简单,因为只能抓http和https数据包,所以在针对 ...

  5. web界面上的字体兼容方案

    原贴地址:http://www.baidufe.com/item/60cd11d3bfdee5c51369.html 做前端的,对web界面基本都抠的很仔细,尤其精确到1px! 类似边距.宽度.高度等 ...

  6. 20-从零玩转JavaWeb-Super关键字与子类初始化过程

    配套详解视频  super关键字 继承内存分析 this与super对比 继承字段隐藏 继承Object根类 一.Super关键字的作用 this:当前对象,谁调用this所在的方法,this就是哪一 ...

  7. PHP 使用memcached简单示例分享

    1.添加扩展包 代码如下: php_memcache.dll 2.在PHP.INI添加  代码如下: extension=php_memcache.dll 3.程序 代码如下: < ?php / ...

  8. C# XML 操作

    1 xml文件格式 <?xml version="1.0" encoding="utf-8"?> <userInfo> <user ...

  9. Timer中的重要函数

  10. Tornado 接口的实现