luogu P4514ybtoj树状数组课堂过关差分 例题6区间修改区间查询 & 上帝造题的七分钟

Posted SSL_ZZL

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了luogu P4514ybtoj树状数组课堂过关差分 例题6区间修改区间查询 & 上帝造题的七分钟相关的知识,希望对你有一定的参考价值。

【例题6】区间修改区间查询 & 上帝造题的七分钟


Link

luogu P4514 上帝造题的七分钟
ybtoj 【树状数组课堂过关】 【例题6】区间修改区间查询
题面//因为不知道侵不侵权所以就是题面是私密的,有账号的直接看转送门就可了


题目大意

给一个矩阵A,有两个操作

  • 1 a, b, c, d, s=》 A ( a 到 c ) , ( b 到 d ) A_{(a到c),(b到d)} A(ac),(bd)+s
  • 2 a, b, c, d =》求 A ( a 到 c ) , ( b 到 d ) A_{(a到c),(b到d)} A(ac),(bd)的和

解题思路

对,捡了道紫题的便宜

很明显,这种矩阵(区间)加值要用差分
【例题4】区间修改区间查询 这是道一维的差分题,但是这题是二维的

设a[][]是实际数组,s[][]是差分数组
a [ i ] [ j ] = ∑ k = 1 i ∑ l = 1 j s [ k ] [ l ] a[i][j]=∑_{k=1}^{i}∑_{l=1}^{j}s[k][l] a[i][j]=k=1il=1js[k][l]

差分时记得要容斥

add(a, b, s); 
add(a, d + 1, -s); 
add(c + 1, b, -s); 
add(c + 1, d + 1, s); 

设f[i][j]是矩阵 A ( 1 到 i ) , ( 1 到 j ) A_{(1到i),(1到j)} A(1i),(1j)的和,那么
f [ i ] [ j ] = ∑ i a = 1 n ∑ j a = 1 m a [ i a ] [ j a ] = ∑ i s = 1 n ∑ j s = 1 m ∑ k = 1 i a ∑ l = 1 j a s [ k ] [ l ] f[i][j]=∑_{ia=1}^n∑_{ja=1}^ma[ia][ja]=∑_{is=1}^{n}∑_{js=1}^m∑_{k=1}^{ia}∑_{l=1}^{ja}s[k][l] f[i][j]=ia=1nja=1ma[ia][ja]=is=1njs=1mk=1ial=1jas[k][l]

和一维一样,考虑每个s[][]的出现次数
有点复杂,是不会讲的,所以。。。推篇博客

ybtoj和luogu的输入不太一样


Code

ybtoj版

#include <iostream>
#include <cstdio>
#define ll long long

using namespace std;

int n, m, a, b, c, d, now;
ll s, tree_s[3000][3000], tree_i[3000][3000], tree_j[3000][3000], tree_ij[3000][3000];

int lowbit(int x) {return (x & -x);}

void add(int x, int y, ll s) {
	for(int i = x; i <= n; i += lowbit(i))
		for(int j = y; j <= m; j += lowbit(j)) {
			tree_s[i][j] += s;
			tree_i[i][j] += s * x;
			tree_j[i][j] += s * y;
			tree_ij[i][j] += s * x * y;
		}
}

ll sum(int x, int y) {
	ll ans = 0;
	for(int i = x; i; i -= lowbit(i))
		for(int j = y; j; j -= lowbit(j))
			ans += tree_s[i][j] * (x + 1) * (y + 1) - tree_i[i][j] * (y + 1) - tree_j[i][j] * (x + 1) + tree_ij[i][j];
	return ans;
}

int main() {
	scanf("%d %d", &n, &m);
	while(scanf("%d", &now) != EOF) {
		scanf("%d %d %d %d", &a, &b, &c, &d);
		if (now == 1) {
			scanf("%lld", &s);
			add(a, b, s); 
			add(a, d + 1, -s); 
			add(c + 1, b, -s); 
			add(c + 1, d + 1, s); 
		} else {
			printf("%lld\\n", sum(c, d) - sum(a - 1, d) - sum(c, b - 1) + sum(a - 1, b - 1)); 
		}
	}
}

luogu版

#include <iostream>
#include <cstdio>

using namespace std;

char now;
int n, m, a, b, c, d;
int s, tree_s[3000][3000], tree_i[3000][3000], tree_j[3000][3000], tree_ij[3000][3000];

int lowbit(int x) {return (x & -x);}

void add(int x, int y, int s) {
	for(int i = x; i <= n; i += lowbit(i))
		for(int j = y; j <= m; j += lowbit(j)) {
			tree_s[i][j] += s;
			tree_i[i][j] += s * x;
			tree_j[i][j] += s * y;
			tree_ij[i][j] += s * x * y;
		}
}

int sum(int x, int y) {
	int ans = 0;
	for(int i = x; i; i -= lowbit(i))
		for(int j = y; j; j -= lowbit(j))
			ans += tree_s[i][j] * (x + 1) * (y + 1) - tree_i[i][j] * (y + 1) - tree_j[i][j] * (x + 1) + tree_ij[i][j];
	return ans;
}

int main() {
	scanf("X %d %d", &n, &m);
	while(~scanf("%s", &now)) {
		scanf("%d %d %d %d", &a, &b, &c, &d);
		if (now == 'L') {
			scanf("%d", &s);
			add(a, b, s); 
			add(a, d + 1, -s); 
			add(c + 1, b, -s); 
			add(c + 1, d + 1, s); 
		} else {
			printf("%d\\n", sum(c, d) - sum(a - 1, d) - sum(c, b - 1) + sum(a - 1, b - 1)); 
		}
	}
}

以上是关于luogu P4514ybtoj树状数组课堂过关差分 例题6区间修改区间查询 & 上帝造题的七分钟的主要内容,如果未能解决你的问题,请参考以下文章

luogu UVA12983ybtoj例题3树状数组严格上升子序列数&The Battle of Chibi

luogu P4513ybtoj线段树课堂过关例题3小白逛公园

ybtoj 单调队列课堂过关luogu P1886例题1滑动窗口

luogu UVA10559 ybtoj 区间DP课堂过关 例题3消除木块 & 方块消除 Blocks

luogu P4170ybtoj 区间DP课堂过关 例题2木板涂色 & [CQOI2007]涂色

luogu P1352ybtoj 树形DP课堂过关 例题1树上求和 & 没有上司的舞会