ARC069F Flags

Captain_Paul

2018-09-27 08:01:44

Personal

题意:有$n$个旗子,第$i$个可以放在$x_i$或$y_i$,求它们两两之间最短距离的最大值 ------------ 二分答案+$2-SAT$+线段树优化 每个旗子要么放在$x_i$要么放在$y_i$,不难想到用$2-SAT$ 将$x_i$记为$i$号元素,$y_i$记为$i+n$号元素(对立点) 二分出一个最短距离$k$ 对于每个点二分出与它的权值差的绝对值小于$k$的区间$[l,r]$ 如果选择了这个区间中的点,那么这个点就不能选 这样就构造出了$2-SAT$模型 因为是区间向点连边,所以用线段树优化建图 总复杂度$O(nlog^2n)$ ``` #include<cstdio> #include<cstring> #include<cctype> #include<algorithm> #define reg register #define reset(a) memset(a,0,sizeof(a)) using namespace std; typedef pair<int,int> par; const int N=1e5+5; struct E { int to,nxt; }edge[N*50]; struct node { int x,id; inline friend bool operator < (node a,node b) {return a.x<b.x;} }c[N]; int n,m,num,head[N],a[N],dfn[N],low[N],bel[N]; int cnt,tim,tot,stack[N],top,idx[N]; bool exist[N]; inline int read() { int x=0,w=1; char c=getchar(); while (!isdigit(c)&&c!='-') c=getchar(); if (c=='-') c=getchar(),w=-1; while (isdigit(c)) { x=(x<<1)+(x<<3)+c-'0'; c=getchar(); } return x*w; } inline void add_edge(int from,int to) { edge[++num]=(E){to,head[from]}; head[from]=num; } inline void clear() { reset(dfn); reset(low); reset(bel); reset(exist); reset(head); reset(idx); num=cnt=tot=top=0; tim=n<<1; } void tarjan(int k) { int temp; dfn[k]=low[k]=++cnt; stack[++top]=k; exist[k]=1; for (reg int i=head[k];i;i=edge[i].nxt) { int v=edge[i].to; if (!dfn[v]) { tarjan(v); low[k]=min(low[k],low[v]); } else if (exist[v]) low[k]=min(low[k],dfn[v]); } if (dfn[k]==low[k]) { ++tot; do { temp=stack[top--]; exist[temp]=0; bel[temp]=tot; }while (temp!=k); } } void build(int l,int r,int now) { idx[now]=++tim; if (now>1) add_edge(idx[now>>1],tim); if (l==r) {add_edge(idx[now],c[l].id>n?c[l].id-n:c[l].id+n); return;} int mid=(l+r)>>1; build(l,mid,now<<1); build(mid+1,r,now<<1|1); } void change(int L,int R,int l,int r,int now,int x) { if (l>R||r<L) return; if (l>=L&&r<=R) {add_edge(x,idx[now]); return;} int mid=(l+r)>>1; if (mid>=R) change(L,R,l,mid,now<<1,x); else if (mid<L) change(L,R,mid+1,r,now<<1|1,x); else { change(L,mid,l,mid,now<<1,x); change(mid+1,R,mid+1,r,now<<1|1,x); } } inline par query(int p,int k) { par ret; ret.first=ret.second=p; int l=1,r=p,pos=p; while (l<=r) { int mid=(l+r)>>1; if (c[p].x-c[mid].x<k) pos=mid,r=mid-1; else l=mid+1; } ret.first=pos; l=p,r=m,pos=p; while (l<=r) { int mid=(l+r)>>1; if (c[mid].x-c[p].x<k) pos=mid,l=mid+1; else r=mid-1; } ret.second=pos; return ret; } inline bool check(int k) { clear(); build(1,m,1); for (reg int i=1;i<=m;i++) { par now=query(i,k); change(now.first,i-1,1,m,1,c[i].id); change(i+1,now.second,1,m,1,c[i].id); } for (reg int i=1;i<=m;i++) if (!dfn[i]) tarjan(i); for (reg int i=1;i<=n;i++) if (bel[i]==bel[i+n]) return 0; return 1; } int main() { n=read(); for (reg int i=1;i<=n;i++) { a[i]=read(),a[i+n]=read(); c[++m]=(node){a[i],i}; c[++m]=(node){a[i+n],i+n}; } sort(c+1,c+m+1); int l=0,r=1e9,ans=0; while (l<=r) { int mid=(l+r)>>1; if (check(mid)) ans=mid,l=mid+1; else r=mid-1; } printf("%d\n",ans); return 0; } ```