[??记录]AT2336 [ARC069D] Flags
command_block
2021-05-12 14:39:08
**题意** : 将 $N$ 个标志放在数轴上。第 $i$ 个标志可以放置在坐标 $a_i$ 或 $b_i$ 上。
求出两个标志之间最小距离的最大值。
$n\leq 10^4$ ,时限$\texttt{5s}$。
------------
先二分答案,然后用 $\text{2-sat}$ 判定。
枚举点标志 $i$ ,对于另标志 $j$ ,按如下规则连边。
- $|a_i-a_j|\leq mid$ : $a_i\rightarrow b_j$
- $|b_i-a_j|\leq mid$ : $b_i\rightarrow b_j$
- $|a_i-b_j|\leq mid$ : $a_i\rightarrow a_j$
- $|b_i-b_j|\leq mid$ : $b_i\rightarrow a_j$
缩点后,若 $a_i,b_i$ 在同一个联通块内,则无解。
不难用(两颗)线段树优化建边。复杂度为 $O(n\log^2 n)$。
常数大得有点离谱……
```cpp
#include<algorithm>
#include<cstdio>
#define ll long long
#define MaxN 10500
using namespace std;
struct Line{int t,nxt;}l[MaxN*200];
int fir[MaxN*4],tl;
void adl(int u,int v)
{l[++tl]=(Line){v,fir[u]};fir[u]=tl;}
int dfn[MaxN*4],low[MaxN*4],tim,stk[MaxN*4],top,col[MaxN*4],Bcnt;
void tar(int u)
{
dfn[stk[++top]=u]=low[u]=++tim;
for (int i=fir[u],v;i;i=l[i].nxt)
if (!dfn[v=l[i].t])
{tar(v);low[u]=min(low[u],low[v]);}
else if (!col[v])low[u]=min(low[u],dfn[v]);
if (low[u]==dfn[u]){
Bcnt++;
while(stk[top+1]!=u)
col[stk[top--]]=Bcnt;
}
}
int wfl,wfr,wfc,tn,n;
struct SGT
{
int p[MaxN<<2],lp[MaxN];
void build(int l=1,int r=n,int u=1)
{
if (l==r){p[u]=lp[l];return ;}
int mid=(l+r)>>1;p[u]=++tn;
build(l,mid,u<<1);
build(mid+1,r,u<<1|1);
adl(p[u],p[u<<1]);adl(p[u],p[u<<1|1]);
}
void add(int l=1,int r=n,int u=1)
{
if (wfl<=l&&r<=wfr){adl(wfc,p[u]);return ;}
int mid=(l+r)>>1;
if (wfl<=mid)add(l,mid,u<<1);
if (mid<wfr)add(mid+1,r,u<<1|1);
}
}Ta,Tb;
int a[MaxN],b[MaxN],xa[MaxN],xb[MaxN],ta[MaxN],tb[MaxN];
bool chk(int lim)
{
for (int i=1;i<=tn;i++)dfn[i]=fir[i]=col[i]=0;
tl=0;tn=2*n;
Ta.build();Tb.build();
for (int i=1;i<=n;i++){
wfc=i;
int l=a[i]-lim+1,r=a[i]+lim-1,mid=ta[i];
wfl=lower_bound(xa+1,xa+n+1,l)-xa;wfr=mid-1;
if (wfl<=wfr)Ta.add();
wfl=mid+1;wfr=upper_bound(xa+1,xa+n+1,r)-xa-1;
if (wfl<=wfr)Ta.add();
wfl=lower_bound(xb+1,xb+n+1,l)-xb;
wfr=upper_bound(xb+1,xb+n+1,r)-xb-1;
if (wfl<=wfr)Tb.add();
wfc=i+n;
l=b[i]-lim+1,r=b[i]+lim-1;
wfl=lower_bound(xa+1,xa+n+1,l)-xa;
wfr=upper_bound(xa+1,xa+n+1,r)-xa-1;
if (wfl<=wfr)Ta.add();
mid=tb[i];
wfl=lower_bound(xb+1,xb+n+1,l)-xb;wfr=mid-1;
if (wfl<=wfr)Tb.add();
wfl=mid+1;wfr=upper_bound(xb+1,xb+n+1,r)-xb-1;
if (wfl<=wfr)Tb.add();
}
for (int i=1;i<=2*n;i++)
if (!dfn[i])tar(i);
for (int i=1;i<=n;i++)
if (col[i]==col[i+n])return 0;
return 1;
}
bool cmpA(int A,int B){return a[A]<a[B];}
bool cmpB(int A,int B){return b[A]<b[B];}
int main()
{
scanf("%d",&n);
for (int i=1;i<=n;i++){
scanf("%d%d",&a[i],&b[i]);
xa[i]=a[i];xb[i]=b[i];
Ta.lp[i]=Tb.lp[i]=i;
}
sort(Ta.lp+1,Ta.lp+n+1,cmpA);sort(Tb.lp+1,Tb.lp+n+1,cmpB);
for (int i=1;i<=n;i++){
ta[Ta.lp[i]]=tb[Tb.lp[i]]=i;
Ta.lp[i]+=n;
}sort(xa+1,xa+n+1);sort(xb+1,xb+n+1);
int l=0,r=1000000000,mid;
while(l<r){
mid=(l+r+1)>>1;
if (chk(mid))l=mid;
else r=mid-1;
}printf("%d",r);
return 0;
}
```