zroi 24noip 十连测 day2 T4 题解

Description

小凯有两个长度为 NN 的整数序列 A1,A2,,ANA_1,A_2,\cdots,A_NB1,B2,,BNB_1,B_2,\cdots,B_N

小凯现在越来越喜欢对称的东西了,当他看到两个序列 C,DC,D 时,他会找到序列 CC 的最小值 CminCminDD 的最小值 DminDmin,他认为这两个最小值相差越小越好,所以他定义 f(C,D)=CminDminf(C,D)=|Cmin-Dmin|

更进一步的,他定义 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) 的值,即 {Al,Al+1,,Ar}\{A_l,A_{l+1},\cdots,A_r\} 的最小值和 {Bl,Bl+1,,Br}\{B_l,B_{l+1},\cdots,B_r\} 的最小值的差的绝对值。

对于每个 k=1,2,,Nk=1,2,\cdots,N,小凯想求出所有长度为 kk 的区间 [l,r][l,r] 中,w(l,r)w(l,r) 的最小值,即求 minrl+1=kw(l,r)\min_{r-l+1=k} w(l,r)

1N2×105,1Ai,Bi1091\leq N\leq 2\times 10^5,1\leq A_i,B_i\leq 10^9

Solution

首先直接做显然是没有任何性质的,考虑分治。

假设当前处理的是区间 [L,R][L,R]mid=(L+R)/2mid=(L+R)/2,考虑跨越 [L,mid][L,mid][mid+1,R][mid+1,R] 的贡献。

  • ai=min{Ai,Ai+1,,Amid}a_i=\min\left\{A_i,A_{i+1},\ldots,A_{mid}\right\}
  • bi=min{Bi,Bi+1,,Bmid}b_i=\min\left\{B_i,B_{i+1},\ldots,B_{mid}\right\}
  • ci=min{Amid+1,Amid+2,,Ai}c_i=\min\left\{A_{mid+1},A_{mid+2},\ldots,A_{i}\right\}
  • di=min{Amid+1,Amid+2,,Ai}d_i=\min\left\{A_{mid+1},A_{mid+2},\ldots,A_{i}\right\}

那么对于一个跨越 midmid 的区间 [l,r][l,r] 的答案就是 min{al,cr}min{bl,dr}\left|\min\left\{a_l,c_r\right\}-\min\left\{b_l,d_r\right\}\right|

枚举 rlr-l,令 k=rlk=r-lw(l,r)w(l,r) 转化为 min{al,cl+k}min{bl,dl+k}\left|\min\left\{a_l,c_{l+k}\right\}-\min\left\{b_l,d_{l+k}\right\}\right|。由于 a,ba,b 是不降的,c,dc,d 是不增的,所以可以二分出 w(l,r)=albl,aldr,crbl,crdrw(l,r)=|a_l-b_l|,|a_l-d_r|,|c_r-b_l|,|c_r-d_r| 分别对应的连续的区间。

对于 w(l,r)=albl 或 crdrw(l,r)=|a_l-b_l|\ 或\ |c_r-d_r| 的情况可以用线段树维护区间最小值。

而对于 w(l,r)=aldrw(l,r)=|a_l-d_r| 的情况,因为 ala_l 不降且 drd_r 不增,所以固定区间长度后 w(l,r)w(l,r) 关于 ll 是个单谷函数,于是二分出 aldra_l\geq d_r 的最大 llal<dra_l<d_r 的最小 ll 即可。w(l,r)=crblw(l,r)=|c_r-b_l| 的情况同理。

时间复杂度:O(nlog2n)O(n\log^2n)

Code

1
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>

// #define int int64_t

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;
// std::cin >> T;
while (T--) dickdreamer();
// std::cerr << 1.0 * clock() / CLOCKS_PER_SEC << "s\n";
return 0;
}

zroi 24noip 十连测 day2 T4 题解
https://sobaliuziao.github.io/2024/09/08/post/a597110.html
作者
Egg_laying_master
发布于
2024年9月8日
许可协议