【ARC069F】Flags【2-SAT】【二分】【线段树】

题解:二分答案+线段树优化连边+2-SAT。
二分答案mid,可以发现每个点要向连续的一段区间内的点连边,离散化后线段树优化连边即可。然后跑2-SAT判定是否有解。

#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<map>
using namespace std;
const int N=10005,M=1000005,K=60005;
int n,l,r,mid,ans,cnt,x[N],y[N],h[N*2],id[N*2],head[K],to[M],nxt[M];
int idx,tot,dfn[K],low[K],scc[K],stk[K];
map<int,int> mp;
void adde(int u,int v){
    to[++cnt]=v;
    nxt[cnt]=head[u];
    head[u]=cnt;
}
namespace sgt{
    int root,tot,ch[K][2];
    void init(){
        root=tot=0;
    }
    void build(int &o,int l,int r){
        if(l==r){
            o=id[l];
            return;
        }
        o=++tot;
        int mid=(l+r)/2;
        build(ch[o][0],l,mid);
        build(ch[o][1],mid+1,r);
        adde(o,ch[o][0]);
        adde(o,ch[o][1]);
    }
    void update(int o,int l,int r,int L,int R,int x){
        if(L<=l&&R>=r){
            adde(x,o);
            return;
        }
        int mid=(l+r)/2;
        if(L<=mid){
            update(ch[o][0],l,mid,L,R,x);
        }
        if(R>mid){
            update(ch[o][1],mid+1,r,L,R,x);
        }
    }
}
void tarjan(int u){
    dfn[u]=low[u]=++idx;
    stk[++stk[0]]=u;
    int v;
    for(int i=head[u];i;i=nxt[i]){
        v=to[i];
        if(!dfn[v]){
            tarjan(v);
            low[u]=min(low[u],low[v]);
        }else if(!scc[v]){
            low[u]=min(low[u],dfn[v]);
        }
    }
    if(low[u]==dfn[u]){
        tot++;
        do{
            scc[stk[stk[0]]]=tot;
        }while(stk[stk[0]--]!=u);
    }
}
void init(){
    cnt=idx=tot=0;
    memset(head,0,sizeof(head));
    memset(dfn,0,sizeof(dfn));
    memset(low,0,sizeof(low));
    memset(scc,0,sizeof(scc));
    sgt::init();
}
bool check(){
    init();
    sgt::tot=2*n;
    sgt::build(sgt::root,1,h[0]);
    for(int i=1;i<=n;i++){
        int l=lower_bound(h+1,h+h[0]+1,h[x[i]]-mid+1)-h;
        int r=upper_bound(h+1,h+h[0]+1,h[x[i]]+mid-1)-h-1;
        if(l<=r){
            if(l<x[i]){
                sgt::update(sgt::root,1,h[0],l,x[i]-1,i+n);
            }
            if(x[i]<r){
                sgt::update(sgt::root,1,h[0],x[i]+1,r,i+n);
            }
        }
        l=lower_bound(h+1,h+h[0]+1,h[y[i]]-mid+1)-h;
        r=upper_bound(h+1,h+h[0]+1,h[y[i]]+mid-1)-h-1;
        if(l<=r){
            if(l<y[i]){
                sgt::update(sgt::root,1,h[0],l,y[i]-1,i);
            }
            if(y[i]<r){
                sgt::update(sgt::root,1,h[0],y[i]+1,r,i);
            }
        }
    }
    for(int i=1;i<=sgt::tot;i++){
        if(!dfn[i]){
            tarjan(i);
        }
    }
    for(int i=1;i<=n;i++){
        if(scc[i]==scc[i+n]){
            return false;
        }
    }
    return true;
}
int main(){
    scanf("%d",&n);
    for(int i=1;i<=n;i++){
        scanf("%d%d",&x[i],&y[i]);
        h[++h[0]]=x[i];
        h[++h[0]]=y[i];
    }
    sort(h+1,h+h[0]+1);
    for(int i=1;i<=h[0];i++){
        if(h[i]!=h[i-1]){
            mp[h[i]]=i;
        }
    }
    for(int i=1;i<=n;i++){
        int tmp=x[i];
        x[i]=mp[tmp];
        mp[tmp]++;
        tmp=y[i];
        y[i]=mp[tmp];
        mp[tmp]++;
        id[x[i]]=i;
        id[y[i]]=i+n;
    }
    l=0,r=1e9;
    while(l<=r){
        mid=(l+r)/2;
        if(check()){
            ans=mid;
            l=mid+1;
        }else{
            r=mid-1;
        }
    }
    printf("%d\n",ans);
    return 0;
}
posted @ 2018-08-09 14:12  ez_2016gdgzoi471  阅读(174)  评论(0编辑  收藏  举报