这是一个很菜的 Oier 的博客|

Hanx16Msgr

园龄:2年8个月粉丝:12关注:3

2023-07-11 17:59阅读: 33评论: 0推荐: 0

P6109 [Ynoi2019] rprmq1

Luogu P6109 [Ynoi2009] rprmq1

Luogu P6109

题目背景

我谔谔

本题读入量约 13 MB,输出量约 7 MB,请选择合适的输入输出方法

题目描述

有一个 n×n 的矩阵 a,初始全是 0,有 m 次修改操作和 q 次查询操作,先进行所有修改操作,然后进行所有查询操作。

一次修改操作会给出 l1,l2,r1,r2,x,代表把所有满足 l1ir1l2jr2ai,j 元素加上一个值 x

一次查询操作会给出 l1,l2,r1,r2,代表查询所有满足 l1ir1l2jr2ai,j 元素的最大值。

输入格式

第一行三个由空格分隔的整数 n,m,q

之后 m 行,每行给出五个整数 l1,l2,r1,r2,x,表示一次修改操作。

之后 q 行,每行给出四个整数 l1,l2,r1,r2,表示一次查询操作。

输出格式

输出 q 行,对每次查询操作输出一行一个数表示答案。

样例 #1

样例输入 #1

5 5 5
1 1 4 5 4
4 1 4 1 10
1 3 3 3 3
1 1 5 5 8
2 4 4 5 8
2 1 2 1
4 1 5 4
1 2 3 5
2 1 5 3
1 3 5 5

样例输出 #1

12
22
20
22
20

提示

Idea:apiadu,Solution:ccz181078,Code:apiadu,Data:apiadu&nzhtl1477

注意:本题采用捆绑测试,只有当你通过一个 subtask 中的所有测试点后,你才能拿到这个 subtask 的分数。

对于其中 1% 的数据,为样例 1。

对于另外 9% 的数据,n=1

对于另外 19% 的数据,n,m500

对于另外 19% 的数据,n2000q2×105

对于另外 19% 的数据,m,q2000

对于 100% 的数据,1n,m5×1041q5×1051x21474836471l1r1n1l2r2n

Solution

首先原问题是二维的,考虑压缩到一维加上时间轴的方式来解决。对于每一次修改操作 (l1,r1,l2,r2,v) 可以转化为在 l1 时间将 [l2,r2] 增加 v,然后在 r1+1 的时间将 [l2,r2] 增加 v。那么询问 (l1,r1,l2,r2) 变成了求 l1r1 时间内区间 [l2,r2] 的历史最值。题目中强调修改操作都在询问之前,明示离线分治。

考虑线段树分治,用外层线段树表示时间这一轴,对于一个线段树上的节点 [l,r],将包含在这个区间内的询问分类为:左右端点都在 [l,mid] 内,左右端点都在 (mid,r],左右端点分居 mid 两侧。容易发现只需要讨论第三种询问,前两种询问都可以通过递归到子树内解决。

既然所有的询问都跨越 mid 这一点,那么考虑将询问时间段 [l,r] 拆分为 [l,mid][mid+1,r]。那么可以先将 [l,mid] 时间的修改加入,然后逐个加入 [mid+1,r] 的修改,同时计算右端点为当前位置的询问的答案。撤销这部分修改,递归进入右子树。逐步撤销 [l,mid] 的修改,然后计算左端点为当前位置的询问的答案。递归进入左子树。

需要用到支持区间加,区间历史最值的线段树,参考P4314 CPU 监控

#include<bits/stdc++.h>
using namespace std;
using i64 = long long;
using ui64 = unsigned long long;
using Ldouble = long double;
#define fir first
#define sec second
#define MP make_pair
template<class T> void read(T &x) {
	x = 0; bool flag = 0; char b = getchar();
	while (!isdigit(b)) flag = b == '-' ? 1 : 0, b = getchar();
	while (isdigit(b)) x = x * 10 + b - 48, b = getchar();
	x = flag ? -x : x;
}
template<class T, class ...Args> void read(T &x, Args &...args) {
	read(x), read(args...);
}
constexpr int _N = 5e5 + 5, _Q = 5e5 + 5;
int n, m, q;
#define LC (k << 1)
#define RC (k << 1 | 1)
#define mid ((l + r) >> 1)
template<class T> void Max(T &x, T y) { x = max(x, y); }
namespace SGT {
	i64 maxn[_N << 2], hmax[_N << 2], tag1[_N << 2], tag2[_N << 2];
	bool Isres[_N << 2];
	void Pushup(int k) {
		maxn[k] = max(maxn[LC], maxn[RC]);
		hmax[k] = max(hmax[LC], hmax[RC]);
	}
	void Add(int k, i64 v1, i64 v2) {
		Max(tag2[k], tag1[k] + v2);
		Max(hmax[k], maxn[k] + v2);
		maxn[k] += v1, tag1[k] += v1;
	}
	void Reset(int k) {
		Add(LC, tag1[k], tag2[k]), Add(RC, tag1[k], tag2[k]);
		Isres[k] = 1, hmax[k] = maxn[k], tag1[k] = tag2[k] = 0;
	}
	void Pushdown(int k) {
		if (Isres[k]) {
			Reset(LC), Reset(RC);
			Isres[k] = 0;
		}
		Add(LC, tag1[k], tag2[k]), Add(RC, tag1[k], tag2[k]);
		tag1[k] = tag2[k] = 0;
	}
	void Update(int k, int l, int r, int a, int b, i64 v) {
		if (l > b || r < a) return ;
		if (l >= a && r <= b) return Add(k, v, v);
		Pushdown(k);
		Update(LC, l, mid, a, b, v), Update(RC, mid + 1, r, a, b, v);
		Pushup(k);
	}
	i64 Query(int k, int l, int r, int a, int b) {
		if (l > b || r < a) return 0;
		if (l >= a && r <= b) return hmax[k];
		Pushdown(k);
		return max(Query(LC, l, mid, a, b), Query(RC, mid + 1, r, a, b));
	}
}
struct Query { int id, l, r, x, y; };
struct Node { int l, r; i64 v; };
vector<Query> que[_N << 2];
vector<Node> vec[_N];
void AddQuery(int k, int l, int r, Query v) {
	if (v.l <= mid + 1 && v.r >= mid) {
		que[k].push_back(v);
		return ;
	}
	if (v.r <= mid) AddQuery(LC, l, mid, v);
	else AddQuery(RC, mid + 1, r, v);
}
void Add(int x) {
	for (auto s : vec[x]) SGT::Update(1, 1, n, s.l, s.r, s.v);
}
void Remove(int x) {
	for (int i = vec[x].size() - 1; i >= 0; --i) {
		auto s = vec[x][i];
		SGT::Update(1, 1, n, s.l, s.r, -s.v);
	}
}
i64 ans[_Q];
bool cmp1(Node A, Node B) { return A.v < B.v; }
bool cmp2(Query A, Query B) { return A.r < B.r; }
bool cmp3(Query A, Query B) { return A.l > B.l; }
void Solve(int k, int l, int r) {
	for (int i = l; i <= mid; ++i) Add(i);
	int p = 0, siz = que[k].size();
	sort(que[k].begin(), que[k].end(), cmp2);
	while (p < siz && que[k][p].r == mid) ++p;
	for (int i = mid + 1; i <= r; ++i) {
		Add(i);
		if (i == mid + 1) SGT::Reset(1);
		while (p < siz && que[k][p].r == i) {
			Max(ans[que[k][p].id], SGT::Query(1, 1, n, que[k][p].x, que[k][p].y));
			++p;
		}
	} 
	for (int i = r; i >= mid + 1; --i) Remove(i);
	if (l != r) Solve(RC, mid + 1, r);
	p = 0;
	sort(que[k].begin(), que[k].end(), cmp3);
	while (p < siz && que[k][p].l == mid + 1) ++p;
	for (int i = mid; i >= l; --i) {
		if (i == mid) SGT::Reset(1);
		while (p < siz && que[k][p].l == i) {
			Max(ans[que[k][p].id], SGT::Query(1, 1, n, que[k][p].x, que[k][p].y));
			++p;
		}
		Remove(i);
	}
	if (l != r) Solve(LC, l, mid);
} 
signed main() {
	ios::sync_with_stdio(0); cout.tie(0);
	read(n, m, q);
	for (int i = 1; i <= m; ++i) {
		int l, r, x, y, v;
		read(l, x, r, y, v);
		vec[l].push_back((Node){ x, y, v });
		vec[r + 1].push_back((Node){ x, y, -v });
	}
	for (int i = 1; i <= q; ++i) {
		int l, r, x, y;
		read(l, x, r, y);
		AddQuery(1, 1, n, (Query){ i, l, r, x, y });
	}
	for (int i = 1; i <= n; ++i)
		sort(vec[i].begin(), vec[i].end(), cmp1);
	Solve(1, 1, n);
	for (int i = 1; i <= q; ++i) cout << ans[i] << '\n';
}
posted @   Hanx16Msgr  阅读(33)  评论(0编辑  收藏  举报
历史上的今天:
2022-07-11 P2466 [SDOI2008] Sue 的小球
2022-07-11 #P2088. 上升序列
2022-07-11 #P2056. ABCD
2022-07-11 #P2030. 交错匹配
2022-07-11 #P2057. 游戏
点击右上角即可分享
微信分享提示
评论
收藏
关注
推荐
深色
回顶
收起