影片連結:
[ARC069F] Flags - 洛谷 | 電腦科學教育新生態 (luogu.com.cn)
// D46 2-SAT+線段樹最佳化+二分 O(nlognlogv) #include <iostream> #include <cstring> #include <algorithm> 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; struct F{ int pos,id; bool operator<(const F& b)const{return pos<b.pos;} F(int pos=0):pos(pos){} }f[N]; int n,tot,id[M]; 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); } 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 m){ 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].pos-m))-f; y=upper_bound(f+1,f+1+2*n,F(f[i].pos+m-1))-f-1; link(1,1,2*n,x,i-1,f[i].id); //x是距離<m的左下標 link(1,1,2*n,i+1,y,f[i].id); //y是距離<m的右下標 } 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].pos,&f[i+n].pos); f[i].id=i,f[i+n].id=i+n; // } sort(f+1,f+n*2+1); //按pos排序 int l=0,r=f[2*n].pos-f[1].pos+1,m; while(l+1<r){ //二分距離 m=(l+r)/2; check(m)?l=m:r=m; } printf("%d",l); }