CF484-E. Sign on Fence 【整体二分】

20 篇文章 0 订阅
6 篇文章 0 订阅

传送门
给定长度为 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) lenlog(max)的时间内找到答案,
l e n len len为区间长度,也就是每次暴力在区间找是否存在连续 w w w小于等于当前判定答案的值的复杂度
多个询问, m ∗ l e n ∗ l o g ( m a x ) m*len*log(max) mlenlog(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;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Hexrt

客官,请不要给我小费!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值