向前走莫回头❤

【bzoj 1176】[Balkan2007] Mokia(cdq分治+树状数组)

1176: [Balkan2007]Mokia

Time Limit: 30 Sec  Memory Limit: 162 MB
Submit: 1852  Solved: 820
[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

HINT

保证答案不会超过int范围

Source

[Submit][Status][Discuss]

【题解】【cdq分治】

【cdq分治,把操作一起二分。因为是二维求和,首先想到的应该是二维线段树或二维树状数组,然而,这范围、、、TLE+MLE!】

【那么,考虑一个经典的解决方法,一维排序、一维树状数组维护前缀和。】

【因为询问的是一个子矩阵和,那么把整个矩阵拆分为4块,两块需要减去、两块需要加上。(刚开始没拆开,用加正负数来处理,WA啊WA!)so把每个询问拆成两个,x为一个,x1为一个,都是求前缀和,最后用后一个减前一个得到答案】

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
struct slove{
	int x,y,y1,k;
	int num,opt,mark,sum;
	int t;
}a[2000010];
int tree[2000010],ans[2000010],pd[2000010];
int s,w,cnt,tot;

int tmp(slove a,slove b)
{
	return a.x<b.x||a.x==b.x&&a.opt<b.opt;
}
int cmp(slove a,slove b)
{
	return a.num<b.num||a.num==b.num&&a.mark<b.mark;
}
inline int lowbit(int x)
{
	return x&(-x);
}
inline void add(int x,int val)
{
	while(x<=w)
	 {
	 	tree[x]+=val;
	 	x+=lowbit(x);
	 }
}
inline int ask(int x)
{
	int ss=0;
	while(x)
	 {
	 	ss+=tree[x];
	 	x-=lowbit(x);
	 }
	return ss;
}
void cdq(int l,int r)
{
	if(l==r) return;
	int mid=(l+r)>>1;
	cdq(l,mid); cdq(mid+1,r);
	sort(a+l,a+mid+1,tmp);
	sort(a+mid+1,a+r+1,tmp);
	int j=l;
	for(int i=mid+1;i<=r;++i)
	 if(a[i].opt==2)
	  {
	  	while(j<=mid&&a[j].x<=a[i].x) 
		 {
		 	if(a[j].opt==1) add(a[j].y,a[j].k);
		    ++j;
		 }
	  	a[i].sum+=ask(a[i].y1)-ask(a[i].y);
	  }
	for(int i=l;i<j;++i) 
	 if(a[i].opt==1) add(a[i].y,-a[i].k);
}
int main()
{
	int i;
	scanf("%d%d",&s,&w);
	while((scanf("%d",&a[++cnt].opt)==1)&&a[cnt].opt!=3)
	 {
	 	tot++;
	 	if(a[cnt].opt==1) scanf("%d%d%d",&a[cnt].x,&a[cnt].y,&a[cnt].k),a[cnt].num=tot;
	 	 else
	 	  {
	 	  	int x,y,x1,y1;  pd[tot]=1;
	 	  	scanf("%d%d%d%d",&x,&y,&x1,&y1);
	        a[cnt].x=x-1; a[cnt].y=y-1; a[cnt].y1=y1; a[cnt].num=tot; a[cnt].mark=-1;
			cnt++; a[cnt].opt=2; a[cnt].x=x1; a[cnt].y=y-1; a[cnt].y1=y1; a[cnt].num=tot; a[cnt].mark=1;	  	
		   }
	 }
	cnt--;
	cdq(1,cnt);
	for(i=1;i<=cnt;++i) 
	  ans[a[i].num]+=a[i].sum*a[i].mark;
	for(i=1;i<=tot;++i)
	 if(pd[i]) printf("%d\n",ans[i]);
	return 0;
}


posted @ 2016-09-10 15:30  lris0-0  阅读(91)  评论(0编辑  收藏  举报
过去的终会化为美满的财富~o( =∩ω∩= )m