传送门
给定长度为
N
N
N的数组
若干个三元组
{
l
,
r
,
w
}
\{l,r,w\}
{l,r,w},要求在原数组
l
l
l ~
r
r
r 区间内(左右闭区间),长度刚好为
w
w
w 的最大矩形高度
分析
这题找最大值存在单调性
如果当前答案为
x
x
x时,能够找到长度恰好为
w
w
w的矩形,那么
∀
y
<
=
x
\forall{y<=x}
∀y<=x 都可行,必然能找到长度为
w
w
w的矩形,
因此对于一个询问来说,可以在
l
e
n
∗
l
o
g
(
m
a
x
)
len*log(max)
len∗log(max)的时间内找到答案,
l
e
n
len
len为区间长度,也就是每次暴力在区间找是否存在连续
w
w
w个小于等于当前判定答案的值的复杂度
多个询问,
m
∗
l
e
n
∗
l
o
g
(
m
a
x
)
m*len*log(max)
m∗len∗log(max)显然不能接受
但是我们发现,对于每个询问我们都会二分进行判断,最后决策答案要么在左边,要么在右边,因此这里有决策单调性,可以考虑整体二分
我们将询问看作一个集合!称为问集,答案区间称为解集!
初始询问在一个问集中,解集在初始数值集合中(排序)
二分嘛。对解集进行二分,对问集进行决策
对于每一个询问
如果判定其解是在左边,则放在左边临时问集中
如果在右边则放在右边临时问集中
这样就能进行递归处理答案了
相似的题有
细节:
由于每次是根据01序列线段数维护的
需要对线段树进行清空,但是如果分治的操作复杂度和区间长度成比例的话,效率是最差的,所以我们得考虑减小复杂度
我们考虑每次会对判定造成影响的每一个位置上的点。
假如一个点在这次二分造成了影响
对于决策在左边解集的问集来说,此点值一定是大于左边解集的值的,也就是说此点一直是固定值,不必更新,所以将小的点给左边解集,这些点才能更新左边的值,同理右边也是如此
代码
//CF484E
/*
@Author: YooQ
*/
#include <bits/stdc++.h>
using namespace std;
#define sc scanf
#define pr printf
#define ll long long
#define int long long
#define FILE_OUT freopen("out", "w", stdout);
#define FILE_IN freopen("in", "r", stdin);
#define debug(x) cout << #x << ": " << x << "\n";
#define AC 0
#define WA 1
#define INF 0x3f3f3f3f
const ll MAX_N = 1e6+5;
const ll MOD = 1e9+7;
int N, M, K;
int arr[MAX_N];
bool brr[MAX_N];
int uni[MAX_N];
int ucnt = 0;
struct Tr {
int k, l, r, len;
Tr operator + (const Tr& B) const {
Tr res;
res.len = len + B.len;
res.k = max(max(k, B.k), r + B.l);
res.l = (l==len)?l+B.l:l;
res.r = (B.r==B.len)?B.r+r:B.r;
return res;
}
}tr[MAX_N];
void push_up(int rt) {
tr[rt] = tr[rt<<1] + tr[rt<<1|1];
}
void build(int rt, int l, int r) {
tr[rt].len = r - l + 1;
if (l == r) {
tr[rt].k = tr[rt].l = tr[rt].r = 0;
return;
}
int mid = l + ((r-l)>>1);
build(rt<<1, l, mid);
build(rt<<1|1, mid+1, r);
push_up(rt);
}
void update(int rt, int l, int r, int x, int k) {
if (l == r) {
tr[rt].k = tr[rt].l = tr[rt].r = k;
return;
}
int mid = l + ((r-l)>>1);
if (x <= mid) update(rt<<1, l, mid, x, k);
if (x > mid) update(rt<<1|1, mid+1, r, x, k);
push_up(rt);
}
Tr query(int rt, int l, int r, int x, int y) {
if (x <= l && r <= y) {
return tr[rt];
}
int mid = l + ((r-l)>>1);
if (y <= mid) return query(rt<<1, l, mid, x, y);
if (x > mid) return query(rt<<1|1, mid+1, r, x, y);
return query(rt<<1, l, mid, x, y) + query(rt<<1|1, mid+1, r, x, y);
}
struct Qr{
int id, l, r, w;
}qr[MAX_N], tmp[MAX_N];
int ans[MAX_N];
struct Point{
int id, x;
}point[MAX_N], tmp2[MAX_N];
void div(int l, int r, int x, int y, int px, int py) {
if (l > r) return;
int mid = l + ((r-l)>>1);
int lp = px;
int rp = py;
for (int i = px; i <= py; ++i) {
if (point[i].x >= uni[mid]) {
tmp2[rp--] = point[i];
update(1, 1, N, point[i].id, 1);
} else {
tmp2[lp++] = point[i];
}
}
for (int i = px; i <= py; ++i) {
point[i] = tmp2[i];
}
int lx = x;
int rx = y;
for (int i = x; i <= y; ++i) {
if (query(1, 1, N, qr[i].l, qr[i].r).k >= qr[i].w) {
ans[qr[i].id] = uni[mid];
tmp[rx--] = qr[i];
} else {
tmp[lx++] = qr[i];
}
}
for (int i = x; i <= y; ++i) {
qr[i] = tmp[i];
}
div(l, mid-1, x, lx-1, px, lp-1);
for (int i = px; i <= py; ++i) {
if (point[i].x >= uni[mid]) {
update(1, 1, N, point[i].id, 0);
}
}
div(mid+1, r, lx, y, lp, py);
}
void solve(){
sc("%lld", &N);
for (int i = 1; i <= N; ++i) {
sc("%lld", &arr[i]);
point[i] = {i, arr[i]};
uni[++ucnt] = arr[i];
}
sort(uni+1, uni+1+ucnt);
ucnt = unique(uni+1, uni+1+ucnt) - uni - 1;
sc("%lld", &M);
for (int i = 1; i <= M; ++i) {
qr[i].id = i;
sc("%lld%lld%lld", &qr[i].l, &qr[i].r, &qr[i].w);
}
build(1, 1, N);
div(1, ucnt, 1, M, 1, N);
for (int i = 1; i <= M; ++i) {
pr("%lld\n", ans[i]);
}
}
signed main()
{
#ifndef ONLINE_JUDGE
//FILE_IN
FILE_OUT
#endif
int T = 1;//cin >> T;
while (T--) solve();
return AC;
}