鏈接:AT2336 Flags
(題意不解釋了)
解法:2-sat + tarjan-scc + 線段樹/分塊
(話說2-sat這東西我讀成二坐,zh大佬每次都要糾正我233333)
使用2-sat建模,將每個點 拆爲 與 ,題目轉化爲選點問題。一條邊 表示若選擇了 ,則 必須被選擇。這東西有啥用呢?由於輸入的每對數要麼必須選 ,要麼必須選 ,也就是說若我們能用2-sat推出“選 必須選 ”那麼問題解決。
考慮如何連邊。首先二分答案,設答案爲 ,那麼我們用線段樹優化連邊(或使用分塊優化連邊),將所有讀入的值排序,對於一個點 ,在排序的值中二分查找區間 ,讓 上的每個數與 的相對差均小於 ,然後由於二分出的答案爲 ,所以若 區間上的選了,則 不能選,從而 必須選,於是將 區間上的每個點向 連邊。
判斷時,先求出所有強連通分量,若某個點 與 處於同一強連通分量內,那麼即是說:若 選了,則 必須選,與題設矛盾,驗證返回僞。
時間複雜度:線段樹連邊 ,分塊連邊 ,均可過。
代碼(只有線段樹版本的,我太懶了QAQ)
#include<iostream>
#include<cstdio>
#include<vector>
#include<cstring>
#include<stack>
#include<algorithm>
using namespace std;
struct data{
int x,i;
data():x(0),i(0){}
data(int y,int j):x(y),i(j){}
friend bool operator<(const data &dt1,const data &dt2){return dt1.x<dt2.x;}
};
stack<int> s;
int n,x[80001],idx,tot,id[80001],low[80001],dfn[80001],scc,cid[80001];
vector<data> vec;
vector<int> point[80001];
void build(int o,int l,int r){
id[o]=++tot;
if(o>1)point[id[o>>1]].push_back(tot);
if(l==r){int v=vec[l-1].i;point[id[o]].push_back(v<=n?v+n:v-n);return;}
int m=l+r>>1;
build(o<<1,l,m),build(o<<1|1,m+1,r);
}
void update(int o,int l,int r,int a,int b,int x){
if(a>b)return;
if(l==a&&r==b){point[x].push_back(id[o]);return;}
int m=l+r>>1;
if(m>=b)update(o<<1,l,m,a,b,x);else if(m<a)update(o<<1|1,m+1,r,a,b,x);else update(o<<1,l,m,a,m,x),update(o<<1|1,m+1,r,m+1,b,x);
}
pair<int,int> get(int i,int m){
pair<int,int> res;int l=1,r=i,mid;
while(l<=r)if(vec[i-1].x-vec[(mid=l+r>>1)-1].x>=m)l=mid+1;else r=mid-1;
res.first=r+1,l=i,r=n<<1;
while(l<=r)if(vec[(mid=l+r>>1)-1].x-vec[i-1].x<m)l=mid+1;else r=mid-1;
res.second=l-1;
return res;
}
void dfs(int u){
low[u]=dfn[u]=++idx;s.push(u);
for(int v:point[u])if(!dfn[v]){dfs(v);low[u]=min(low[u],low[v]);}else if(dfn[v]>0)low[u]=min(low[u],dfn[v]);
if(low[u]==dfn[u]){int x;++scc;while(x!=u)x=s.top(),s.pop(),dfn[x]=-dfn[x],cid[x]=scc;}
}
bool check(int m){
memset(low,scc=idx=0,sizeof(low)),memset(dfn,0,sizeof(dfn));for(int i=1;i<=80000;++i)point[i].clear();
build(1,1,tot=n<<1);
for(int i=1;i<=n<<1;++i){int r=vec[i-1].i;pair<int,int> pr=get(i,m);update(1,1,n<<1,pr.first,i-1,r),update(1,1,n<<1,i+1,pr.second,r);}
for(int i=1;i<=n<<1;++i)if(!dfn[i])dfs(i);
for(int i=1;i<=n;++i)if(cid[i]==cid[i+n])return false;
return true;
}
int main(){
scanf("%d",&n);
for(int i=1;i<=n;++i)scanf("%d%d",x+i,x+n+i),vec.push_back(data(x[i],i)),vec.push_back(data(x[i+n],i+n));
sort(vec.begin(),vec.end());
int l=0,r=1000000000,m;while(l<=r)if(check(m=l+r>>1))l=m+1;else r=m-1;
printf("%d",l-1);
}