飘扬的旗帜
我也不知道哪里蒯来的题。反正二分 + 2-sat + 线段树优化连边就完事了。
注意答案可能为0..
1 #include <bits/stdc++.h> 2 3 const int N = 100010; 4 5 struct Edge { 6 int nex, v; 7 }edge[3000010]; int tp; 8 9 struct Node { 10 int x, f; 11 Node(int X = 0, int F = 0) { 12 x = X; 13 f = F; 14 } 15 }; 16 17 int e[N], num, dfn[N], low[N], X[N], xx, tot, n, fr[N], scc_cnt, ls[N], rs[N]; 18 std::vector<Node> v[N]; 19 int stk[N], top, rt, A[N], B[N]; 20 21 inline void add(int x, int y) { 22 tp++; 23 edge[tp].v = y; 24 edge[tp].nex = e[x]; 25 e[x] = tp; 26 return; 27 } 28 29 inline void clear() { 30 memset(e + 1, 0, tot * sizeof(int)); 31 memset(dfn + 1, 0, tot * sizeof(int)); 32 memset(fr + 1, 0, tot * sizeof(int)); 33 tp = top = num = scc_cnt = 0; 34 return; 35 } 36 37 void tarjan(int x) { 38 low[x] = dfn[x] = ++num; 39 stk[++top] = x; 40 for(int i = e[x]; i; i = edge[i].nex) { 41 int y = edge[i].v; 42 if(!dfn[y]) { 43 tarjan(y); 44 low[x] = std::min(low[x], low[y]); 45 } 46 else if(!fr[y]) { 47 low[x] = std::min(low[x], dfn[y]); 48 } 49 } 50 if(low[x] == dfn[x]) { 51 ++scc_cnt; 52 int y; 53 do { 54 y = stk[top]; 55 top--; 56 fr[y] = scc_cnt; 57 } while(y != x); 58 } 59 return; 60 } 61 62 void Add(int L, int R, int v, int l, int r, int &o) { 63 if(!o) o = ++tot; 64 if(L <= l && r <= R) { 65 add(v, o); 66 return; 67 } 68 int mid = (l + r) >> 1; 69 if(L <= mid) Add(L, R, v, l, mid, ls[o]); 70 if(mid < R) Add(L, R, v, mid + 1, r, rs[o]); 71 return; 72 } 73 74 void build(int f, int l, int r, int &o) { 75 if(!o) o = ++tot; 76 if(f) add(f, o); 77 if(l == r) { 78 for(int i = 0; i < (int)v[r].size(); i++) { 79 if(v[r][i].f) { 80 add(o, v[r][i].x); 81 } 82 else { 83 add(o, v[r][i].x + n); 84 } 85 } 86 return; 87 } 88 int mid = (l + r) >> 1; 89 build(o, l, mid, ls[o]); 90 build(o, mid + 1, r, rs[o]); 91 return; 92 } 93 94 inline bool check(int k) { 95 96 clear(); 97 for(int i = 1; i <= n; i++) { 98 int l = std::lower_bound(X + 1, X + xx + 1, X[A[i]] - k) - X; 99 int r = std::upper_bound(X + 1, X + xx + 1, X[A[i]] + k) - X - 1; 100 int mid = A[i]; 101 if(l < mid) { 102 Add(l, mid - 1, i, 1, xx, rt); 103 } 104 if(mid < r) { 105 Add(mid + 1, r, i, 1, xx, rt); 106 } 107 for(int j = 0; j < (int)v[mid].size(); j++) { 108 if(v[mid][j].x == i) continue; 109 if(v[mid][j].f) { 110 add(i, v[mid][j].x); 111 } 112 else { 113 add(i, v[mid][j].x + n); 114 } 115 } 116 l = std::lower_bound(X + 1, X + xx + 1, X[B[i]] - k) - X; 117 r = std::upper_bound(X + 1, X + xx + 1, X[B[i]] + k) - X - 1; 118 mid = B[i]; 119 if(l < mid) { 120 Add(l, mid - 1, i + n, 1, xx, rt); 121 } 122 if(mid < r) { 123 Add(mid + 1, r, i + n, 1, xx, rt); 124 } 125 for(int j = 0; j < (int)v[mid].size(); j++) { 126 if(v[mid][j].x == i) continue; 127 if(v[mid][j].f) { 128 add(i + n, v[mid][j].x); 129 } 130 else { 131 add(i + n, v[mid][j].x + n); 132 } 133 } 134 } 135 build(0, 1, xx, rt); 136 for(int i = 1; i <= tot; i++) { 137 if(!dfn[i]) { 138 tarjan(i); 139 } 140 } 141 for(int i = 1; i <= n; i++) { 142 if(fr[i] == fr[i + n]) return 0; 143 } 144 return 1; 145 } 146 147 int main() { 148 149 scanf("%d", &n); 150 tot = n << 1; 151 for(int i = 1; i <= n; i++) { 152 scanf("%d%d", &A[i], &B[i]); 153 X[++xx] = A[i]; X[++xx] = B[i]; 154 } 155 std::sort(X + 1, X + xx + 1); 156 xx = std::unique(X + 1, X + xx + 1) - X - 1; 157 for(int i = 1; i <= n; i++) { 158 A[i] = std::lower_bound(X + 1, X + xx + 1, A[i]) - X; 159 B[i] = std::lower_bound(X + 1, X + xx + 1, B[i]) - X; 160 v[A[i]].push_back(Node(i, 0)); 161 v[B[i]].push_back(Node(i, 1)); 162 } 163 164 int l = -1, r = X[xx] - X[1]; 165 while(l < r) { 166 int mid = (l + r + 1) >> 1; 167 if(check(mid)) { 168 l = mid; 169 } 170 else { 171 r = mid - 1; 172 } 173 } 174 175 printf("%d\n", r + 1); 176 return 0; 177 }
我这个写法不对,如果离散化了就不能暴力处理单个位置的其他边,因为可能会被卡成n²。正确的方法是不离散化或者对每个位置再用一个前后缀优化连边。