1176: [Balkan2007]Mokia

1176: [Balkan2007]Mokia

Time Limit: 30 Sec   Memory Limit: 162 MB
Submit: 1399   Solved: 594
[ Submit][ Status][ Discuss]

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



CDQ分治。。
对时间二分,每次执行前半段时间的操作,加给后半段询问
对于询问将它拆为四个点,每个点都维护从左上角到该点的和
加的话用扫描线+树状数组就是了
(花了苟蒻一下午。。。。)

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<vector>
#include<queue>
using namespace std;

const int maxn = 4E5 + 20;
const int maxm = 2E6 + 20;

struct Q{
	int x,y,c,typ,pos;
	bool operator < (const Q &b) const {
		if (x < b.x) return 1;
		if (x > b.x) return 0;
		return typ < b.typ;
	}
}src[maxn],t[maxn];

int c[maxm],n,m,s;

void CDQ(int l,int r)
{
	if (l == r) return;
	int mid = (l+r) >> 1;
	CDQ(l,mid);
	int cur = 0;
	for (int i = l; i <= mid; i++)
		if (src[i].typ == 1) 
			t[++cur] = src[i];
	for (int i = mid+1; i <= r; i++)
		if (src[i].typ == 2)
			t[++cur] = src[i],t[cur].pos = i;
	sort(t+1,t+cur+1);
	for (int i = 1; i <= cur; i++) {
		if (t[i].typ == 1) {
			for (int j = t[i].y; j <= m; j += j&-j)
				c[j] += t[i].c;
		}
		else {
			for (int j = t[i].y; j > 0; j -= j&-j)
				src[t[i].pos].c += c[j];
		}
	}
	for (int i = 1; i <= cur; i++) 
		if (t[i].typ == 1)
			for (int j = t[i].y; j <= m; j += j&-j)
				c[j] -= t[i].c;
	CDQ(mid+1,r);
}

int main()
{
	#ifdef YZY
		   freopen("yzy.txt","r",stdin);
	#endif
	
	cin >> s >> m;
	int cnt = 0;
	for (;;) {
		int X1,X2,Y1,Y2,typ;
		scanf("%d",&typ);
		if (typ == 3) break;
		if (typ == 1) {
			++cnt;
			src[cnt].typ = 1;
			scanf("%d%d%d",&src[cnt].x,&src[cnt].y,&src[cnt].c);
		}
		else {
			scanf("%d%d%d%d",&X1,&Y1,&X2,&Y2);
			++cnt;
			src[cnt].typ = 2; src[cnt].c = s*(X2-X1+1)*(Y2-Y1+1);
			src[cnt].x = X2; src[cnt].y = Y2;
			++cnt;
			src[cnt].typ = 2;
			src[cnt].x = X2; src[cnt].y = Y1 - 1;
			++cnt;
			src[cnt].typ = 2;
			src[cnt].x = X1 - 1; src[cnt].y = Y2;
			++cnt;
			src[cnt].typ = 2;
			src[cnt].x = X1 - 1; src[cnt].y = Y1 - 1;
		}
	}
	
	CDQ(1,cnt);
	for (int i = 1; i <= cnt; i++) 
		if (src[i].typ == 2) {
			int ans = 0;
			ans += src[i++].c;
			ans -= src[i++].c;
			ans -= src[i++].c;
			ans += src[i].c;
			printf("%d\n",ans);
		}
	return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值