12
5
2015
0

1176: [Balkan2007]Mokia

1176: [Balkan2007]Mokia

Description

维护一个W*W的矩阵,初始值均为S.每次操作可以增加某格子的权值,或询问某子矩阵的总权值.修改操作数M<=160000,询问数Q<=10000,W<=2000000.

Input

第一行两个整数,S,W;其中S为矩阵初始值;W为矩阵大小

接下来每行为一下三种输入之一(不包含引号):

"1 x y a"

"2 x1 y1 x2 y2"

"3"

输入1:你需要把(x,y)(第x行第y列)的格子权值增加a

输入2:你需要求出以左上角为(x1,y1),右下角为(x2,y2)的矩阵内所有格子的权值和,并输出

输入3:表示输入结束

Output

对于每个输入2,输出一行,即输入2的答案

Sample Input

0 4
1 2 3 3
2 1 1 3 3
1 2 2 2
2 2 2 3 4
3

Sample Output

3
5

HINT

 

保证答案不会超过int范围

 

 

 

CDQ分治

 

首先提一个求矩阵和的经典思路:

将矩阵转化成 由1,1为左下角的矩阵 的 和差

即矩阵[x1,y1,x2,y2] (以左下角和右上角点的坐标表示矩阵)

可表示为[x1,y1,x2,y2] = [1,1,x2,y2] - [1,1,x1 -1,y2] - [1,1,x2,y2 -1] + [1,1,x1 -1,y1 -1]

 

所以这道题求矩阵和即可转化为求四个以(1,1)为坐下角的矩阵

 

一个位置的点(a,b)对某矩阵[1,1,x,y]的和有贡献

当且仅当满足 a <= x 且 b <= y

 

而对于每个修改操作,可以理解为增加某一点对其余点的贡献

 

所以 这道题就可以完美地转化为 BZOJ3262 了

 

最后一点不同就是,3262的每个操作既是添加,也是询问

本题的操作有单独的添加和询问之分

只有在二分左半段有一添加操作时,添加

只有在二分右半段有一询问操作是,询问

然后,没有了。。。

 

#include <cstdio>
#include <algorithm>
using namespace std;
const int MaxN = 200010;
const int MaxW = 2000010;
int W, S, N;
struct opt{
	int o, x, y, key, k;
	opt (int p = 0,int a = 0, int b = 0, int s = 0, int w = 0) {
		o = p; x = a; y = b; key = s; k = w;
	}
}p[MaxN],q[MaxN];
int sum[MaxW];
inline int lowbit(int x){
	return x & -x;
}
inline void New(int x){
	for (; x <= W; x += lowbit(x))
	    if (sum[x]) sum[x] = 0;
	    else break;
}
inline void Insert(int x, int k){
	for (; x <= W; x += lowbit(x))
	    sum[x] += k;
}
inline int Query(int x){
	int res = 0;
	for (; x; x -= lowbit(x))
	    res += sum[x];
	return res;
}
inline void solve(int l, int r){
	if (l == r) return;
	int mid = l + r >> 1;
	solve(l, mid), solve(mid + 1, r);
	
	int t1 = l, t2 = mid + 1;
	for (int i = l; i <= r; ++i)
	    if (t1 <= mid && p[t1].x <= p[t2].x || t2 > r) {
	    	q[i] = p[t1++];
	    	if (q[i].o % 2) Insert(q[i].y, q[i].key);
		}
		else {
	    	q[i] = p[t2++];
			if (!(q[i].o % 2)) q[i].key += Query(q[i].y);
		}
	for (int i = l; i <= r; ++i)
	    p[i] = q[i], New(q[i].y);
}
bool cmp (const opt &a, const opt &b){
	return a.k < b.k;
}
int main(){
	scanf("%d%d", &S, &W);
	for (;;){
		int o, x1, y1, x2, y2, k;
		scanf("%d",&o);
		if (o == 3) break;
		if (o % 2) {
			scanf("%d%d%d", &x1, &y1, &k);
			p[++N] = opt(o, x1, y1, k, N);
		}
		else {
			scanf("%d%d%d%d", &x1, &y1, &x2, &y2);
			p[++N] = opt(o, x1 - 1, y1 - 1, 0, N);
			p[++N] = opt(o, x2, y2, 0, N);
			p[++N] = opt(o, x1 - 1, y2, 0, N);
			p[++N] = opt(o, x2, y1 - 1, 0, N);
	    }
	}
	solve(1, N);
	sort(p + 1, p + N + 1, cmp);
	for (int i = 1; i <= N; )
	    if (!(p[i].o % 2)){
	    	int x1 = p[i].x, y1 = p[i].y;
	    	int x2 = p[i + 1].x, y2 = p[i + 1].y;
	    	int ans = p[i].key + p[i + 1].key - p[i + 2].key -p[i + 3].key;
	    	ans += (x2 - x1) * (y2 - y1) * S;
	    	printf("%d\n",ans);
	    	i += 4;
		} 
		else ++i;
} 

 

Category: BZOJ | Tags: bzoj 分治 bit | Read Count: 440

登录 *


loading captcha image...
(输入验证码)
or Ctrl+Enter

Host by is-Programmer.com | Power by Chito 1.3.3 beta | Theme: Aeros 2.0 by TheBuckmaker.com