AT2336 [ARC069D] Flags

题目大意:

(N)个标志放在一条线上,第 (i) 个标志可以放置在坐标 (x_i) 或坐标 (y_i) 上。

(Snuke) 认为当他们中的两个之间的最小距离 (d) 更大时,标志看起来更好。

找出 (d) 的最大可能值。

(n<=10^4,x_i,y_i<=10^9)

solution

每个点只有两种选择,同时每个点选择之间会存在不合法,2-SAT 问题

显然,答案具有二分性

二分一个答案,然后确定那些点不能同时选,向它的对立点连边,

如果一个点的两个位置在一个强连通分量中,那么答案就不合法

连边是 (O(n^2)) 的,会 T

因为每个点可以是对一个区间连边,所以可以把每个点按照位置排个序,线段树优化建图就好了

code

/*
work by:Ariel_
*/
#include<iostream>
#include<cstdio>
#include<stack>
#include<algorithm>
#include<cstring>
#define int long long
#define clear(x) memset(x, 0, sizeof(x))
#define op(x) ((x) <= n ? (x) + n : (x) - n)
#define lson rt << 1
#define rson rt << 1 | 1
using namespace std;
const int N = 3e6 + 5, K = 1e4 + 5; 
int read() {
  int x = 0, f = 1; char c = getchar();
  while(c < '0' || c > '9'){if (c == '-') f = -1;c = getchar();}
  while(c >= '0' && c <= '9') {x = x * 10 + c - '0';c = getchar();}
  return x * f;
}
int n, id[N], ans, cnt;
struct FLAGS{
   int pos, id;
   bool operator<(const FLAGS& f) const { return pos < f.pos; }
   FLAGS(int pos = 0):pos(pos){};
}flg[N];
struct edge{int v, nxt;}e[N];
bool cmp(FLAGS x, FLAGS y){return x.pos < y.pos;}
int head[N], E;
void add_edge(int u, int v) {
   e[++E] = (edge) {v, head[u]};
   head[u] = E;
}
namespace Seg{
   void build(int rt, int l, int r) {
    id[rt] = ++cnt;
    if (l == r) {
        add_edge(id[rt], op(flg[l].id));
        return;
     }
     int mid = (l + r) >> 1;
     build(lson, l, mid), build(rson, mid + 1, r);
     add_edge(id[rt], id[lson]), add_edge(id[rt], id[rson]);
   }
   void modify(int rt, int l, int r, int L, int R, int v) {
   	  if (L > R) return ; 
	  int mid = (l + r) >> 1;
   	  if (l == L && r == R) add_edge(v, id[rt]);
	  else if (R <= mid) modify(lson, l, mid, L, R, v);
	  else if (L > mid) modify(rson, mid + 1, r, L, R, v);
	  else modify(lson, l, mid, L, mid, v), modify(rson, mid + 1, r, mid + 1, R, v); 
   }
}
using namespace Seg;
int vis[N], dfn[N], low[N], tot, sc, scc[N];
stack<int> s;
void tarjan(int x) {
   low[x] = dfn[x] = ++tot;
   s.push(x), vis[x] = 1;
   for (int i = head[x]; i; i = e[i].nxt) {
   	     int v = e[i].v;
   	    if (!dfn[v]) {
   	      tarjan(v);
		  low[x] = min(low[x], low[v]);
		}
		else if(vis[v]) low[x] = min(dfn[v], low[x]);
   }
   int k;
   if (low[x] == dfn[x]) {
   	  sc++;
   	  do{
   	  	k = s.top(), s.pop();
   	  	scc[k] = sc, vis[k] = 0;
	  }while(k != x);
   }
}
bool check(int v) {
  clear(head), clear(low), clear(dfn), clear(e), clear(vis), clear(scc);
  E = tot = cnt = 0;
  build(1, 1, cnt = 2 * n);
  int l, r;
  for (int i = 1; i <= 2 * n; i++) {
  	 l = upper_bound(flg + 1, flg + 2 * n + 1, FLAGS(flg[i].pos - v)) - flg;
  	 r = upper_bound(flg + 1, flg + 2 * n + 1, FLAGS(flg[i].pos + v - 1)) - flg - 1;
  	 modify(1, 1, 2 * n, l, i - 1, flg[i].id), modify(1, 1, 2 * n, i + 1, r, flg[i].id); 
  }
  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;
}
signed main(){
  n = read();
  for (int i = 1; i <= n; i++) {
  	flg[i].pos = read(), flg[i + n].pos = read();
  	flg[i].id = i, flg[i + n].id = i + n;
  }
  sort(flg + 1, flg + 2 * n + 1, cmp);
  int l = 0, r = flg[2 * n].pos - flg[1].pos + 1;
  while(l <= r) {
  	 int mid = (l + r) >> 1;
  	 if (check(mid)) l = mid + 1, ans = mid; 
  	 else r = mid - 1;
  }
  printf("%lld", ans);
  puts("");
  return 0;
}
原文地址:https://www.cnblogs.com/Arielzz/p/15036304.html