Description小凯有两个长度为 N N N 的整数序列 A 1 , A 2 , ⋯ , A N A_1,A_2,\cdots,A_N A 1 , A 2 , ⋯ , A N 和 B 1 , B 2 , ⋯ , B N B_1,B_2,\cdots,B_N B 1 , B 2 , ⋯ , B N 。
小凯现在越来越喜欢对称的东西了,当他看到两个序列 C , D C,D C , D 时,他会找到序列 C C C 的最小值 C m i n Cmin C m i n 和 D D D 的最小值 D m i n Dmin D m i n ,他认为这两个最小值相差越小越好,所以他定义 f ( C , D ) = ∣ C m i n − D m i n ∣ f(C,D)=|Cmin-Dmin| f ( C , D ) = ∣ C m i n − D m i n ∣ 。
更进一步的,他定义 w ( l , r ) w(l,r) w ( l , r ) 表示当 $C={A_l,A_{l+1},\cdots,A_r},D={B_l,B_{l+1},\cdots,B_r} $ 时 f ( C , D ) f(C,D) f ( C , D ) 的值,即 { A l , A l + 1 , ⋯ , A r } \{A_l,A_{l+1},\cdots,A_r\} { A l , A l + 1 , ⋯ , A r } 的最小值和 { B l , B l + 1 , ⋯ , B r } \{B_l,B_{l+1},\cdots,B_r\} { B l , B l + 1 , ⋯ , B r } 的最小值的差的绝对值。
对于每个 k = 1 , 2 , ⋯ , N k=1,2,\cdots,N k = 1 , 2 , ⋯ , N ,小凯想求出所有长度为 k k k 的区间 [ l , r ] [l,r] [ l , r ] 中,w ( l , r ) w(l,r) w ( l , r ) 的最小值,即求 min r − l + 1 = k w ( l , r ) \min_{r-l+1=k} w(l,r) min r − l + 1 = k w ( l , r ) 。
1 ≤ N ≤ 2 × 1 0 5 , 1 ≤ A i , B i ≤ 1 0 9 1\leq N\leq 2\times 10^5,1\leq A_i,B_i\leq 10^9 1 ≤ N ≤ 2 × 1 0 5 , 1 ≤ A i , B i ≤ 1 0 9 。
Solution首先直接做显然是没有任何性质的,考虑分治。
假设当前处理的是区间 [ L , R ] [L,R] [ L , R ] ,m i d = ( L + R ) / 2 mid=(L+R)/2 m i d = ( L + R ) / 2 ,考虑跨越 [ L , m i d ] [L,mid] [ L , m i d ] 和 [ m i d + 1 , R ] [mid+1,R] [ m i d + 1 , R ] 的贡献。
设
a i = min { A i , A i + 1 , … , A m i d } a_i=\min\left\{A_i,A_{i+1},\ldots,A_{mid}\right\} a i = min { A i , A i + 1 , … , A m i d } b i = min { B i , B i + 1 , … , B m i d } b_i=\min\left\{B_i,B_{i+1},\ldots,B_{mid}\right\} b i = min { B i , B i + 1 , … , B m i d } c i = min { A m i d + 1 , A m i d + 2 , … , A i } c_i=\min\left\{A_{mid+1},A_{mid+2},\ldots,A_{i}\right\} c i = min { A m i d + 1 , A m i d + 2 , … , A i } d i = min { A m i d + 1 , A m i d + 2 , … , A i } d_i=\min\left\{A_{mid+1},A_{mid+2},\ldots,A_{i}\right\} d i = min { A m i d + 1 , A m i d + 2 , … , A i } 那么对于一个跨越 m i d mid m i d 的区间 [ l , r ] [l,r] [ l , r ] 的答案就是 ∣ min { a l , c r } − min { b l , d r } ∣ \left|\min\left\{a_l,c_r\right\}-\min\left\{b_l,d_r\right\}\right| ∣ min { a l , c r } − min { b l , d r } ∣ 。
枚举 r − l r-l r − l ,令 k = r − l k=r-l k = r − l ,w ( l , r ) w(l,r) w ( l , r ) 转化为 ∣ min { a l , c l + k } − min { b l , d l + k } ∣ \left|\min\left\{a_l,c_{l+k}\right\}-\min\left\{b_l,d_{l+k}\right\}\right| ∣ min { a l , c l + k } − min { b l , d l + k } ∣ 。由于 a , b a,b a , b 是不降的,c , d c,d c , d 是不增的,所以可以二分出 w ( l , r ) = ∣ a l − b l ∣ , ∣ a l − d r ∣ , ∣ c r − b l ∣ , ∣ c r − d r ∣ w(l,r)=|a_l-b_l|,|a_l-d_r|,|c_r-b_l|,|c_r-d_r| w ( l , r ) = ∣ a l − b l ∣ , ∣ a l − d r ∣ , ∣ c r − b l ∣ , ∣ c r − d r ∣ 分别对应的连续的区间。
对于 w ( l , r ) = ∣ a l − b l ∣ 或 ∣ c r − d r ∣ w(l,r)=|a_l-b_l|\ 或\ |c_r-d_r| w ( l , r ) = ∣ a l − b l ∣ 或 ∣ c r − d r ∣ 的情况可以用线段树维护区间最小值。
而对于 w ( l , r ) = ∣ a l − d r ∣ w(l,r)=|a_l-d_r| w ( l , r ) = ∣ a l − d r ∣ 的情况,因为 a l a_l a l 不降且 d r d_r d r 不增,所以固定区间长度后 w ( l , r ) w(l,r) w ( l , r ) 关于 l l l 是个单谷函数,于是二分出 a l ≥ d r a_l\geq d_r a l ≥ d r 的最大 l l l 和 a l < d r a_l<d_r a l < d r 的最小 l l l 即可。w ( l , r ) = ∣ c r − b l ∣ w(l,r)=|c_r-b_l| w ( l , r ) = ∣ c r − b l ∣ 的情况同理。
时间复杂度:O ( n log 2 n ) O(n\log^2n) O ( n log 2 n ) 。
Code1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 #include <bits/stdc++.h> const int kMaxN = 2e5 + 5 ;int n;int a[kMaxN], b[kMaxN], ans[kMaxN], mila[kMaxN], milb[kMaxN], mira[kMaxN], mirb[kMaxN];struct SGT { int N, mi[kMaxN * 4 ]; void build (int n) { memset (mi, 0x3f , sizeof (mi)); for (N = 1 ; N <= n + 2 ; N <<= 1 ) {} } void update (int x, int v) { mi[x += N] = v; for (x >>= 1 ; x; x >>= 1 ) mi[x] = std::min (mi[x << 1 ], mi[x << 1 | 1 ]); } int query (int l, int r) { int ret = 1e9 ; for (l += N - 1 , r += N + 1 ; l ^ r ^ 1 ; l >>= 1 , r >>= 1 ) { if (~l & 1 ) ret = std::min (ret, mi[l ^ 1 ]); if (r & 1 ) ret = std::min (ret, mi[r ^ 1 ]); } return ret; } } sgt;int func (int x, int k) { return abs (std::min (mila[x], mira[x + k]) - std::min (milb[x], mirb[x + k])); }void solve (int l, int r) { if (l == r) return void (ans[1 ] = std::min (ans[1 ], abs (a[l] - b[l]))); int mid = (l + r) >> 1 ; solve (l, mid), solve (mid + 1 , r); mila[mid] = a[mid], milb[mid] = b[mid], mira[mid + 1 ] = a[mid + 1 ], mirb[mid + 1 ] = b[mid + 1 ]; for (int i = mid - 1 ; i >= l; --i) { mila[i] = std::min (mila[i + 1 ], a[i]); milb[i] = std::min (milb[i + 1 ], b[i]); } for (int i = mid + 2 ; i <= r; ++i) { mira[i] = std::min (mira[i - 1 ], a[i]); mirb[i] = std::min (mirb[i - 1 ], b[i]); } for (int i = l; i <= r; ++i) { if (i <= mid) sgt.update (i, abs (mila[i] - milb[i])); else sgt.update (i, abs (mira[i] - mirb[i])); } for (int k = 1 ; k <= r - l; ++k) { int ll = std::max (l, mid + 1 - k), rr = std::min (mid, r - k); if (ll > rr) continue ; int L = ll - 1 , R = rr + 1 , p1 = ll - 1 , p2 = ll - 1 ; while (L + 1 < R) { int mid = (L + R) >> 1 ; if (mila[mid] <= mira[mid + k]) L = p1 = mid; else R = mid; } L = ll - 1 , R = rr + 1 ; while (L + 1 < R) { int mid = (L + R) >> 1 ; if (milb[mid] <= mirb[mid + k]) L = p2 = mid; else R = mid; } if (ll <= std::min (p1, p2)) ans[k + 1 ] = std::min (ans[k + 1 ], sgt.query (ll, std::min (p1, p2))); if (std::max (p1, p2) < rr) ans[k + 1 ] = std::min (ans[k + 1 ], sgt.query (std::max (p1, p2) + 1 + k, rr + k)); if (p1 == p2) continue ; if (p1 < p2) { int L = p1 + 1 , R = p2 + 1 , res = p1 + 1 ; while (L + 1 < R) { int mid = (L + R) >> 1 ; if (mira[mid + k] >= milb[mid]) L = res = mid; else R = mid; } ans[k + 1 ] = std::min (ans[k + 1 ], func (res, k)); if (res < p2) ans[k + 1 ] = std::min (ans[k + 1 ], func (res + 1 , k)); } else { int L = p2 + 1 , R = p1 + 1 , res = p2 + 1 ; while (L + 1 < R) { int mid = (L + R) >> 1 ; if (mirb[mid + k] >= mila[mid]) L = res = mid; else R = mid; } ans[k + 1 ] = std::min (ans[k + 1 ], func (res, k)); if (res < p1) ans[k + 1 ] = std::min (ans[k + 1 ], func (res + 1 , k)); } } }void dickdreamer () { std::cin >> n; for (int i = 1 ; i <= n; ++i) std::cin >> a[i]; for (int i = 1 ; i <= n; ++i) std::cin >> b[i]; memset (ans, 0x3f , sizeof (ans)); sgt.build (n); solve (1 , n); for (int i = 1 ; i <= n; ++i) std::cout << ans[i] << '\n' ; }int32_t main () {#ifdef ORZXKR freopen ("in.txt" , "r" , stdin); freopen ("out.txt" , "w" , stdout);#endif std::ios::sync_with_stdio (0 ), std::cin.tie (0 ), std::cout.tie (0 ); int T = 1 ; while (T--) dickdreamer (); return 0 ; }