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
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
| struct Tag {
ll add = 0; // 懒标记初始值
Tag(ll add = 0) : add(add) {}
bool empty() const { return add == 0; }
void apply(const Tag& t) { add += t.add; } // 合并懒标记:先已有操作,再做t
};
struct Info {
ll sum = LLONG_MAX / 3;
Info(ll sum = LLONG_MAX / 3) : sum(sum) {}
void apply(const Tag& t, int l, int r) { sum += t.add; } // 把懒标记作用到当前节点
};
Info operator+(const Info& a, const Info& b) { return {min(a.sum, b.sum)}; } // 合并两个Info
bool operator<(const Info& a, const Info& b) { return a.sum < b.sum; } // 线段树二分用,不需要时可删
template <typename Info, typename Tag>
class LazySegmentTree {
int n;
vector<Info> info;
vector<Tag> tag;
void apply(int node, int l, int r, const Tag& v) {
info[node].apply(v, l, r);
tag[node].apply(v);
}
void pushdown(int node, int l, int r) {
if (tag[node].empty()) return;
int m = (l + r) >> 1;
apply(node << 1, l, m, tag[node]);
apply(node << 1 | 1, m + 1, r, tag[node]);
tag[node] = Tag();
} // 把当前节点的懒标记下传
void maintain(int node) { info[node] = info[node << 1] + info[node << 1 | 1]; }
void build(const vector<Info>& a, int node, int l, int r) {
if (l == r) {
info[node] = a[l];
return;
}
int m = (l + r) >> 1;
build(a, node << 1, l, m);
build(a, node << 1 | 1, m + 1, r);
maintain(node);
} // 建树,复杂度O(n)
void update(int node, int l, int r, int ql, int qr, const Tag& v) {
if (ql <= l && r <= qr) {
apply(node, l, r, v);
return;
}
pushdown(node, l, r);
int m = (l + r) >> 1;
if (ql <= m) update(node << 1, l, m, ql, qr, v);
if (qr > m) update(node << 1 | 1, m + 1, r, ql, qr, v);
maintain(node);
} // 区间更新[ql,qr]
void assign(int node, int l, int r, int p, const Info& v) {
if (l == r) {
info[node] = v;
tag[node] = Tag();
return;
}
pushdown(node, l, r);
int m = (l + r) >> 1;
if (p <= m)
assign(node << 1, l, m, p, v);
else
assign(node << 1 | 1, m + 1, r, p, v);
maintain(node);
} // 单点赋值
Info query(int node, int l, int r, int ql, int qr) {
if (ql <= l && r <= qr) return info[node];
pushdown(node, l, r);
int m = (l + r) >> 1;
if (qr <= m) return query(node << 1, l, m, ql, qr);
if (ql > m) return query(node << 1 | 1, m + 1, r, ql, qr);
return query(node << 1, l, m, ql, qr) + query(node << 1 | 1, m + 1, r, ql, qr);
} // 区间查找
template <typename F>
int find_first(int node, int l, int r, int ql, int qr, F&& check) {
if (r < ql || l > qr || !check(info[node])) return -1;
if (l == r) return l;
pushdown(node, l, r);
int m = (l + r) >> 1;
int res = find_first(node << 1, l, m, ql, qr, check);
if (res != -1) return res;
return find_first(node << 1 | 1, m + 1, r, ql, qr, check);
} // 若遇到固定左端点的情况,需要使用全局变量(或者传入引用)记录前缀分段最大值,加一个被待求区间完全覆盖的剪枝
template <typename F>
int find_last(int node, int l, int r, int ql, int qr, F&& check) {
if (r < ql || l > qr || !check(info[node])) return -1;
if (l == r) return l;
pushdown(node, l, r);
int m = (l + r) >> 1;
int res = find_last(node << 1 | 1, m + 1, r, ql, qr, check);
if (res != -1) return res;
return find_last(node << 1, l, m, ql, qr, check);
}
public:
LazySegmentTree(int n, Info init_val = Info()) : LazySegmentTree(vector<Info>(n, init_val)) {}
// 维护下标为[0,n-1],初始值为init_val的区间,或者数组a
LazySegmentTree(const vector<Info>& a) : n(sz(a)), info(2 << bit_width((unsigned)sz(a) - 1)), tag(2 << bit_width((unsigned)sz(a) - 1)) {
build(a, 1, 0, n - 1);
}
// 更新[ql,qr]为f
void update(int ql, int qr, const Tag& v) { update(1, 0, n - 1, ql, qr, v); }
// 单点赋值a[p]=v
void assign(int p, const Info& v) { assign(1, 0, n - 1, p, v); }
// 区间查询[ql,qr]
Info query(int ql, int qr) { return query(1, 0, n - 1, ql, qr); }
template <typename F>
int find_first(int ql, int qr, F&& check) {
return find_first(1, 0, n - 1, ql, qr, check);
} // 查询[ql,qr]中第一个满足条件的下标
template <typename F>
int find_last(int ql, int qr, F&& check) {
return find_last(1, 0, n - 1, ql, qr, check);
} // 查询[ql,qr]中最后一个满足条件的下标
int find_first(int ql, int qr, const Info& val) {
return find_first(ql, qr, [&](const Info& x) { return !(x < val); });
}
int find_last(int ql, int qr, const Info& val) {
return find_last(ql, qr, [&](const Info& x) { return !(x < val); });
}
};
// 注:懒标记线段树无论做什么都需要pushdown
// 此时其它与线段树二分同
void solve() {
ll n, k;
cin >> n >> k;
vl a(n);
rep(i, 0, n - 1) cin >> a[i];
ll l = 0, r = *max_element(all(a)), mid, ans = 0;
auto check = [&](ll mid) -> bool {
vi pre(n), suf(n);
vector<Info> init(n, LLONG_MAX / 3);
LazySegmentTree<Info, Tag> seg(init);
int cnt = 0;
rep(i, 0, n - 1) {
seg.assign(i, Info(mid - a[i]));
while (seg.query(0, n - 1).sum <= 0) {
int tem2 = seg.find_last(0, i, [&](const Info& x) { return x.sum <= 0; });
cnt++;
seg.assign(tem2, Info(LLONG_MAX / 3));
if (tem2 > 0) seg.update(0, tem2 - 1, Tag(-1));
}
pre[i] = cnt;
}
LazySegmentTree<Info, Tag> seg2(init);
cnt = 0;
frep(i, n - 1, 0) {
seg2.assign(i, Info(mid - a[i]));
while (seg2.query(0, n - 1).sum <= 0) {
int tem2 = seg2.find_first(i, n - 1, [&](const Info& x) { return x.sum <= 0; });
cnt++;
seg2.assign(tem2, Info(LLONG_MAX / 3));
if (tem2 < n - 1) seg2.update(tem2 + 1, n - 1, Tag(-1));
}
suf[i] = cnt;
}
int maxx = 0;
rep(i, 0, n - 1) {
if (a[i] >= mid) maxx = max(maxx, pre[i] + suf[i] - 1);
}
return maxx >= n - k;
};
while (l <= r) {
mid = (l + r) / 2;
if (check(mid)) {
ans = mid;
l = mid + 1;
} else
r = mid - 1;
}
cout << ans << endl;
return;
}
|