[BZOJ2653]middle(二分答案 + 主席树)

Address

Solution

  • 很不错的题
  • 求某个排名的数的最值是一个经典的二分答案套路
  • 方法为:二分答案 m i d mid mid 之后,把所有数按照与 m i d mid mid 的大小关系变成 0 0 0 1 1 1 进行判断
  • 而本题也可以先离散化权值之后二分答案 m i d mid mid
  • 把所有 ≥ m i d \ge mid mid 的值变成 1 1 1 &lt; m i d &lt;mid <mid 的值变成 0 0 0
  • 判断左端点在 [ a , b ] [a,b] [a,b] 内,右端点在 [ c , d ] [c,d] [c,d] 内的所有区间中,是否存在一个区间满足 1 1 1 的个数 ≥ \ge 0 0 0 的个数
  • 还是不好算,于是我们考虑把 &lt; m i d &lt;mid <mid 的值变成 − 1 -1 1
  • 判断左端点在 [ a , b ] [a,b] [a,b] 内,右端点在 [ c , d ] [c,d] [c,d] 内的所有区间中,是否存在一个区间的和 ≥ 0 \ge 0 0
  • 考虑分成三段
  • (1) [ a , b ] [a,b] [a,b] 的最大后缀和
  • (2) [ b + 1 , c − 1 ] [b+1,c-1] [b+1,c1] 区间的和
  • (3) [ c , d ] [c,d] [c,d] 的最大前缀和
  • 把这三部分加起来,就是左端点在 [ a , b ] [a,b] [a,b] 内且右端点在 [ c , d ] [c,d] [c,d] 内的所有区间中,最大的区间和
  • 设有 m + 1 m+1 m+1 m m m 为离散化后序列中不同数的个数)棵线段树,分别为第 0 0 0 棵到第 m m m 棵,第 i i i 棵线段树储存当 &gt; i &gt;i >i 的数改成 1 1 1 ≤ i \le i i 的数改成 − 1 -1 1 后的区间和、最大前缀和、最大后缀和
  • 那么查询(1)(3)就只需要在第 m i d − 1 mid-1 mid1 棵线段树上查询下区间最大后缀 / 前缀和即可
  • O ( n log ⁡ 2 n ) O(n\log^2n) O(nlog2n)

Code

#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define For(i, a, b) for (i = a; i <= b; i++)

inline int read()
{
	int res = 0; bool bo = 0; char c;
	while (((c = getchar()) < '0' || c > '9') && c != '-');
	if (c == '-') bo = 1; else res = c - 48;
	while ((c = getchar()) >= '0' && c <= '9')
		res = (res << 3) + (res << 1) + (c - 48);
	return bo ? ~res + 1 : res;
}

template <class T>
inline T Max(const T &a, const T &b) {return a > b ? a : b;}

const int N = 2e4 + 5, L = 7e6 + 5;

int n, a[N], m, b[N], rt[N], q, tmp[4], lst, ToT, pos[N];

struct xpair
{
	int x, y;
} qa[N];

struct tri
{
	int sum, pre, suf;
	
	friend inline tri operator + (tri a, tri b)
	{
		return (tri) {a.sum + b.sum, Max(a.pre, a.sum + b.pre),
			Max(b.suf, b.sum + a.suf)};
	}
};

inline bool comp(xpair a, xpair b)
{
	return a.y < b.y;
}

struct node
{
	int lc, rc; tri a;
} T[L];

void change(int l, int r, int pos, int v, int &p)
{
	if (!p) p = ++ToT;
	if (l == r) return (void) (T[p].a.sum = T[p].a.pre = T[p].a.suf = v);
	int mid = l + r >> 1;
	if (pos <= mid) change(l, mid, pos, v, T[p].lc);
	else change(mid + 1, r, pos, v, T[p].rc);
	T[p].a = T[T[p].lc].a + T[T[p].rc].a;
}

void changeof(int y, int &x, int l, int r, int pos, int v)
{
	T[x = ++ToT] = T[y];
	if (l == r) return (void) (T[x].a.sum = T[x].a.pre = T[x].a.suf = v);
	int mid = l + r >> 1;
	if (pos <= mid) changeof(T[y].lc, T[x].lc, l, mid, pos, v);
	else changeof(T[y].rc, T[x].rc, mid + 1, r, pos, v);
	T[x].a = T[T[x].lc].a + T[T[x].rc].a;
}

tri query(int l, int r, int s, int e, int p)
{
	if (s > e) return (tri) {0, 0, 0};
	if (l == s && r == e) return T[p].a;
	int mid = l + r >> 1;
	if (e <= mid) return query(l, mid, s, e, T[p].lc);
	else if (s >= mid + 1) return query(mid + 1, r, s, e, T[p].rc);
	else return query(l, mid, s, mid, T[p].lc)
		+ query(mid + 1, r, mid + 1, e, T[p].rc);
}

bool check(int a, int b, int c, int d, int mid)
{
	return query(1, n, a, b, rt[pos[mid - 1]]).suf
		+ query(1, n, b + 1, c - 1, rt[pos[mid - 1]]).sum
		+ query(1, n, c, d, rt[pos[mid - 1]]).pre >= 0;
}

int main()
{
	int i;
	n = read();
	For (i, 1, n) a[i] = b[i] = read();
	std::sort(b + 1, b + n + 1);
	m = std::unique(b + 1, b + n + 1) - b - 1;
	For (i, 1, n) a[i] = std::lower_bound(b + 1, b + m + 1, a[i]) - b;
	For (i, 1, n) qa[i] = (xpair) {i, a[i]};
	std::sort(qa + 1, qa + n + 1, comp);
	For (i, 1, n) change(1, n, i, 1, rt[0]);
	For (i, 1, n)
	{
		changeof(rt[i - 1], rt[i], 1, n, qa[i].x, -1);
		pos[qa[i].y] = i;
	}
	q = read();
	while (q--)
	{
		tmp[0] = (read() + lst) % n + 1;
		tmp[1] = (read() + lst) % n + 1;
		tmp[2] = (read() + lst) % n + 1;
		tmp[3] = (read() + lst) % n + 1;
		std::sort(tmp, tmp + 4);
		int l = 1, r = m;
		while (l <= r)
		{
			int mid = l + r >> 1;
			if (check(tmp[0], tmp[1], tmp[2], tmp[3], mid)) l = mid + 1;
			else r = mid - 1;
		}
		printf("%d\n", lst = b[r]);
	}
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
毕设新项目-基于Java开发的智慧养老院信息管理系统源码+数据库(含vue前端源码).zip 【备注】 1、该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的,请放心下载使用!有问题请及时沟通交流。 2、适用人群:计算机相关专业(如计科、信息安全、数据科学与大数据技术、人工智能、通信、物联网、自动化、电子信息等)在校学生、专业老师或者企业员工下载使用。 3、用途:项目具有较高的学习借鉴价值,不仅适用于小白学习入门进阶。也可作为毕设项目、课程设计、大作业、初期项目立项演示等。 4、如果基础还行,或热爱钻研,亦可在此项目代码基础上进行修改添加,实现其他不同功能。 欢迎下载!欢迎交流学习!不清楚的可以私信问我! 毕设新项目-基于Java开发的智慧养老院信息管理系统源码+数据库(含vue前端源码).zip毕设新项目-基于Java开发的智慧养老院信息管理系统源码+数据库(含vue前端源码).zip毕设新项目-基于Java开发的智慧养老院信息管理系统源码+数据库(含vue前端源码).zip毕设新项目-基于Java开发的智慧养老院信息管理系统源码+数据库(含vue前端源码).zip毕设新项目-基于Java开发的智慧养老院信息管理系统源码+数据库(含vue前端源码).zip毕设新项目-基于Java开发的智慧养老院信息管理系统源码+数据库(含vue前端源码).zip毕设新项目-基于Java开发的智慧养老院信息管理系统源码+数据库(含vue前端源码).zip毕设新项目-基于Java开发的智慧养老院信息管理系统源码+数据库(含vue前端源码).zip毕设新项目-基于Java开发的智慧养老院信息管理系统源码+数据库(含vue前端源码).zip
综合小区管理系统管理系统按照操作主体分为管理员和用户。管理员的功能包括报修管理、车位管理、车位分配管理、出入管理、字典管理、房屋管理、物业费缴纳管理、公告管理、物业人员投诉管理、我的私信管理、物业人员管理、用户管理、管理员管理。用户的功能包括管理部门以及部门岗位信息,管理招聘信息,培训信息,薪资信息等。该系统采用了Mysql数据库,Java语言,Spring Boot框架等技术进行编程实现。 综合小区管理系统管理系统可以提高综合小区管理系统信息管理问题的解决效率,优化综合小区管理系统信息处理流程,保证综合小区管理系统信息数据的安全,它是一个非常可靠,非常安全的应用程序。 管理员权限操作的功能包括管理公告,管理综合小区管理系统信息,包括出入管理,报修管理,报修管理,物业费缴纳等,可以管理操作员。 出入管理界面,管理员在出入管理界面中可以对界面中显示,可以对招聘信息的招聘状态进行查看,可以添加新的招聘信息等。报修管理界面,管理员在报修管理界面中查看奖罚种类信息,奖罚描述信息,新增奖惩信息等。车位管理界面,管理员在车位管理界面中新增。公告管理界面,管理员在公告管理界面查看公告的工作状态,可以对公告的数据进行导出,可以添加新公告的信息,可以编辑公告信息,删除公告信息。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值