【JZOJ5446】高考是不可能高考的
###Description
Snuke 喜欢旗子.
Snuke 正在将N 个旗子摆在一条线上.
第i 个旗子可以被放在位置xi 或yi 上.
Snuke 认为两个旗子间的最小距离越大越好. 请你求出最大值.
###Solution
如题,打工是不可能打工的,高考是不可能高考的
看到最小距离最大直接二分答案,考虑怎么判定。
我们先限制一下点对(一个旗子能放的两个位置)的关系(后面说怎么限制)。
然后把所有位置打散,映射到数轴上,对于一个位置 i i i放置旗子,那么区间 [ i − m i d + 1 , i + m i d − 1 ] [i-mid+1,i+mid-1] [i−mid+1,i+mid−1]中所有能放旗子的别的位置都不能放。那么这就是一个经典的2-sat问题。同时点对的限制也是一个2-sat限制关系。
但这题暴力连边可能会T,我们发现一个位置i会向连续的区间连边,于是我们可以对区间建棵线段树,连的时候直接连向对应区间即可。这样连的边数是 O ( n l o g 2 n ) O(nlog_2n) O(nlog2n)条的。
###Code
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#define fo(i,j,k) for(int i=j;i<=k;i++)
#define fd(i,j,k) for(int i=j;i>=k;i--)
#define rep(i,x) for(int i=ls[x];i;i=nx[i])
#define N 10010
#define M 100010
#define inf 2147483647
#define abs(x) ((x)<0?-(x):(x))
using namespace std;
int n;
struct node{
int x,y;
}a[N],b[N*2];
int tot=0;
bool cmp(node x,node y){
return x.x<y.x;
}
int low[M],dfn[M],in[M];
int st[M],tt=0;
int col=0,c[M];
int to[N*100],nx[N*100],ls[M],num=0;
void link(int x,int y){
to[++num]=y,nx[num]=ls[x],ls[x]=num;
}
void tarjan(int x){
low[x]=dfn[x]=++tt,in[st[tt]=x]=true;
rep(i,x){
int v=to[i];
if(!dfn[v]) tarjan(v),low[x]=min(low[x],low[v]);
else if(in[v]) low[x]=min(low[x],dfn[v]);
}
if(low[x]==dfn[x]){
col++;
while(st[tt+1]!=x && tt){
int o=st[tt--];
c[o]=col,in[o]=false;
}
}
}
void clear(){
memset(c,0,sizeof(c)),col=0;
memset(low,0,sizeof(low));
memset(dfn,0,sizeof(dfn));
memset(st,0,sizeof(st));
memset(ls,0,sizeof(ls)),num=0;
}
int nw;
int ans=0;
int jy[N],ne[N*2];
int tr[N*8];
void build(int v,int l,int r){
if(l==r) {tr[v]=l+tot;return;}
int mid=(l+r)>>1;
build(v<<1,l,mid),build((v<<1)+1,mid+1,r);
tr[v]=++nw;
link(tr[v],tr[v<<1]),link(tr[v],tr[(v<<1)+1]);
}
void lk(int v,int l,int r,int x,int y,int t){
if(x>y) return;
if(l==x && r==y){
link(t,tr[v]);
return;
}
int mid=(l+r)>>1;
if(y<=mid) lk(v<<1,l,mid,x,y,t);
else if(x>mid) lk((v<<1)+1,mid+1,r,x,y,t);
else lk(v<<1,l,mid,x,mid,t),lk((v<<1)+1,mid+1,r,mid+1,y,t);
}
bool check(int mid){
clear();
fo(i,1,tot)
if(ne[i]) link(i,ne[i]+tot),link(ne[i]+tot,i),link(i+tot,ne[i]),link(ne[i],i+tot);
nw=tot*2,build(1,1,tot);
int l=1,r=1;
fo(i,1,tot)
{
int wz=b[i].x;
while(r<tot && wz+mid>b[r+1].x) r++;
while(wz-mid>=b[l].x) l++;
lk(1,1,tot,l,i-1,i),lk(1,1,tot,i+1,r,i);
//fo(j,l,r) if(i!=j) link(i,j+n);
}
fo(i,1,tot)
if(!dfn[i]) tarjan(i);
fo(i,1,tot) if(c[i]==c[i+tot] && c[i]) return false;
return true;
}
int main()
{
scanf("%d",&n);
fo(i,1,n){
scanf("%d %d",&a[i].x,&a[i].y);
if(a[i].x>a[i].y) swap(a[i].x,a[i].y);
b[++tot].x=a[i].x,b[tot].y=i;
b[++tot].x=a[i].y,b[tot].y=i;
}
sort(b+1,b+tot+1,cmp);
fo(i,1,tot){
if(jy[b[i].y]) ne[jy[b[i].y]]=i;
jy[b[i].y]=i;
}
int l=0,r=(b[tot].x-b[1].x)/(n-1)+1;
while(l+1<r){
int mid=(l+r)/2;
if(check(mid)) l=mid;
else r=mid;
}
if(check(r)) l=r;
printf("%d",l);
}