【AT2336】Flags

鏈接:AT2336 Flags
(題意不解釋了)

解法:2-sat + tarjan-scc + 線段樹/分塊

(話說2-sat這東西我讀成二坐,zh大佬每次都要糾正我233333)

使用2-sat建模,將每個點i 拆爲ii ,題目轉化爲選點問題。一條邊(u,v) 表示若選擇了u ,則v 必須被選擇。這東西有啥用呢?由於輸入的每對數要麼必須選x ,要麼必須選y ,也就是說若我們能用2-sat推出“選u 必須選u ”那麼問題解決。

考慮如何連邊。首先二分答案,設答案爲m ,那麼我們用線段樹優化連邊(或使用分塊優化連邊),將所有讀入的值排序,對於一個點u ,在排序的值中二分查找區間[l,r] ,讓[l,r] 上的每個數與u 的相對差均小於m ,然後由於二分出的答案爲m ,所以若[l,r] 區間上的選了,則u 不能選,從而u 必須選,於是將[l,r] 區間上的每個點向u 連邊。

判斷時,先求出所有強連通分量,若某個點uu 處於同一強連通分量內,那麼即是說:若u 選了,則u 必須選,與題設矛盾,驗證返回僞。

時間複雜度:線段樹連邊O(Nlog2N) ,分塊連邊O(NNlogN) ,均可過。

代碼(只有線段樹版本的,我太懶了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);
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章