1 条题解

  • 0
    @ 2026-6-22 14:25:07

    D46 2-SAT+线段树优化+二分 [ARC069F] Flags

    // 2-SAT+线段树优化+二分 O(nlognlogx)
    #include<bits/stdc++.h>
    using namespace std;
    
    #define mid ((l+r)>>1)
    #define ls (u<<1)
    #define rs (u<<1|1)
    
    const int N=20010,M=N*10;
    int head[M],ne[N*40],to[N*40],idx;
    void add(int x,int y){
      to[++idx]=y;ne[idx]=head[x];head[x]=idx;
    }
    int dfn[M],low[M],stk[M],scc[M],tim,top,sc;
    int n,tot,id[M];
    struct F{
      int x,id; //坐标,编号
      F(int x=0):x(x){}
      bool operator<(const F& b)const{return x<b.x;}
    }f[N]; //旗子
    
    void build(int u,int l,int r){
      id[u]=++tot; //节点编号
      if(l==r){
        int x=f[l].id;
        add(id[u],x<=n?x+n:x-n); //叶子向反点连边
        return;
      }
      build(ls,l,mid);
      build(rs,mid+1,r);
      add(id[u],id[ls]);
      add(id[u],id[rs]); //父向子连边
    }
    void link(int u,int l,int r,int x,int y,int p){
      if(x>r||y<l) return;
      if(x<=l&&r<=y){
        add(p,id[u]); //p点向区间id[u]连边
        return;
      }
      link(ls,l,mid,x,y,p),
      link(rs,mid+1,r,x,y,p);
    }
    #undef mid
    
    void tarjan(int x){
      dfn[x]=low[x]=++tim;
      stk[++top]=x;
      for(int i=head[x];i;i=ne[i]){
        int y=to[i];
        if(!dfn[y]){ //若y尚未访问
          tarjan(y);
          low[x]=min(low[x],low[y]);
        }
        else if(!scc[y]) //若y已访问且未处理
          low[x]=min(low[x],dfn[y]);
      }
      if(low[x]==dfn[x]){ //若x是SCC的根
        ++sc;
        for(int y=-1;y!=x;)
          scc[y=stk[top--]]=sc;
      }
    }
    bool check(int mid){
      memset(head,0,sizeof(head));
      memset(dfn,0,sizeof(dfn));
      memset(low,0,sizeof(low));
      memset(scc,0,sizeof(scc));
      idx=tim=top=sc=0;
      
      build(1,1,tot=2*n);
      for(int i=1,x,y;i<=2*n;i++){
        x=upper_bound(f+1,f+1+2*n,F(f[i].x-mid))-f;
        y=lower_bound(f+1,f+1+2*n,F(f[i].x+mid))-f-1;
        link(1,1,2*n,x,i-1,f[i].id); //x是距离<mid的左下标
        link(1,1,2*n,i+1,y,f[i].id); //y是距离<mid的右下标
      }
      
      for(int i=1;i<=2*n;i++) if(!dfn[i]) tarjan(i);
      for(int i=1;i<=n;i++) if(scc[i]==scc[i+n]) return 0;
      return 1;
    }
    int main(){
      scanf("%d",&n);
      for(int i=1;i<=n;i++){
        scanf("%d%d",&f[i].x,&f[i+n].x);
        f[i].id=i,f[i+n].id=i+n; //点的编号
      }
      sort(f+1,f+n*2+1); //按x排序
      int l=0,r=f[2*n].x-f[1].x+1,mid;
      while(l+1<r){ //二分距离
        mid=(l+r)/2;
        check(mid)?l=mid:r=mid;
      }
      printf("%d",l);
    }
    
    • 1

    D46 2-SAT+线段树优化+二分 [ARC069F] Flags

    信息

    ID
    9488
    时间
    5000ms
    内存
    256MiB
    难度
    10
    标签
    递交数
    1
    已通过
    1
    上传者