题意:
分析:
挺裸的一道题,直接二分答案,然后建图跑 (2-SAT) 判断合法性
但是会发现复杂度瓶颈在于 (O(n^2)) 建图
我们发现每一次连边都是向距离在 ((min,pos_i-mid)) 和 ((pos_i+mid,max)) 这段区间内的点连边,然后我们就可以用线段树优化建图来将建图的复杂度降低到 (O(nlog ))
tip:
- 按照 (pos) 为关键字对点进行升序排序,建图的时候,每个叶子结点向自己的对应点连一条边,这样连边方式变成了向一段区间内连边,但是一定要少掉自己,即向 ((pos_i-mid,pos_i)) 和 ((pos_i+1,pos_i+mid)) 区间连边
- 由于每次 (check) 会清空 (head) 数组,所以会将建出来的线段树也清掉,所以每次记得重建一次
代码:
#include<bits/stdc++.h>
#define pii pair<int,int>
#define mk(x,y) make_pair(x,y)
#define lc rt<<1
#define rc rt<<1|1
#define pb push_back
#define fir first
#define sec second
#define inl inline
#define reg register
using namespace std;
namespace zzc
{
inline int read()
{
int x=0,f=1;char ch=getchar();
while (!isdigit(ch)){if (ch=='-') f=-1;ch=getchar();}
while (isdigit(ch)){x=x*10+ch-48;ch=getchar();}
return x*f;
}
const int maxn = 2e5+5;
int n,m,top,col,tim,idx,cnt;
int id[maxn],head[maxn],bel[maxn],dfn[maxn],low[maxn],st[maxn];
bool vis[maxn];
struct edge
{
int to,nxt;
}e[maxn<<3];
void add(int u,int v)
{
e[++cnt].to=v;
e[cnt].nxt=head[u];
head[u]=cnt;
}
struct node
{
int pos,id;
node(){}
node(int pos,int id=0):pos(pos),id(id){}
bool operator <(const node &b)const
{
return pos<b.pos;
}
}p[maxn];
int op(int x)
{
return x<=n?x+n:x-n;
}
void build(int rt,int l,int r)
{
id[rt]=++idx;
if(l==r)
{
add(id[rt],op(p[l].id));
return ;
}
int mid=(l+r)>>1;
build(lc,l,mid);build(rc,mid+1,r);
add(id[rt],id[lc]);add(id[rt],id[rc]);
}
void link(int rt,int l,int r,int ql,int qr,int x)
{
if(ql>qr) return ;
if(ql<=l&&r<=qr)
{
add(x,id[rt]);
return ;
}
int mid=(l+r)>>1;
if(ql<=mid) link(lc,l,mid,ql,qr,x);
if(qr>mid) link(rc,mid+1,r,ql,qr,x);
}
void tarjan(int u)
{
dfn[u]=low[u]=++tim;
st[++top]=u;
vis[u]=true;
for(int i=head[u];i;i=e[i].nxt)
{
int v=e[i].to;
if(!dfn[v])
{
tarjan(v);
low[u]=min(low[u],low[v]);
}
else if(vis[v]) low[u]=min(low[u],dfn[v]);
}
if(low[u]==dfn[u])
{
col++;
do
{
bel[st[top]]=col;
vis[st[top]]=false;
}while(st[top--]!=u);
}
}
bool check(int x)
{
for(int i=1;i<=idx;i++) head[i]=0,dfn[i]=0;
cnt=0;tim=0;top=0;
build(1,1,idx=2*n);
for(int i=1;i<=2*n;i++)
{
int l=upper_bound(p+1,p+2*n+1,node(p[i].pos-x))-p;
int r=upper_bound(p+1,p+2*n+1,node(p[i].pos+x-1))-p-1;
link(1,1,2*n,l,i-1,p[i].id);link(1,1,2*n,i+1,r,p[i].id);
}
for(int i=1;i<=2*n;i++) if(!dfn[i]) tarjan(i);
for(int i=1;i<=n;i++) if(bel[i]==bel[i+n]) return false;
return true;
}
void work()
{
n=read();
for(int i=1;i<=n;i++)
{
p[i].pos=read();p[i+n].pos=read();
p[i].id=i;p[i+n].id=i+n;
}
sort(p+1,p+2*n+1);
int l=0,r=p[2*n].pos-p[1].pos+1,mid,ans;
while(l<=r)
{
mid=(l+r)>>1;
if(check(mid))
{
ans=mid;
l=mid+1;
}
else r=mid-1;
}
printf("%d
",ans);
}
}
int main()
{
zzc::work();
return 0;
}