BZOJ1176: [Balkan2007]Mokia(CDQ+树状数组)

题意:N*N的矩形 N<=2e6 操作一 单点更新 操作二 查询矩形区域和 我们用三元组(t,x,y)表示第x操作作用(x,y)坐标 然后对于询问拆成四个答案维护即可 跑CDQ把每部分的答案综合起来即可!

#include <bits/stdc++.h>
#define ll long long
const int NM=2e6+10;
const int nm=2e5+10;
using namespace std;
int read(){
    int x=0,f=1;char ch=getchar();
    while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
    while(isdigit(ch))x=x*10+ch-'0',ch=getchar();
    return f*x;
}
typedef struct node{
	int x,y;int pos,vul;
}node;
node d[nm];ll ans[nm];
node q[nm];
int n,cnt;
int p[NM];
int get_id(int x){return x&(-x);}
void update(int x,int vul){
	if(!x||!vul)return ;
	for(int i=x;i<=n;i+=get_id(i))p[i]+=vul;
}
int Sum(int x){
	int sum=0;
	for(int i=x;i>0;i-=get_id(i))sum+=p[i];
	return sum;
}
void clear(int x){
	if(!x)return ;
	for(int i=x;i<=n;i+=get_id(i))p[i]=0;
}
void gui(int l,int mid,int r){
//	cout<<l<<" "<<mid<<" "<<r<<endl;
	int i=l;int j=mid+1;int num=0;
	while(i<=mid&&j<=r){
		while(i<=mid&&d[i].x<=d[j].x)q[++num]=d[i],update(d[i].y,d[i].vul),i++;
		q[++num]=d[j];
	//	cout<<num<<"---==="<<d[j].y<<endl;
//		update(d[j].y,d[j].vul);
		if(d[j].pos<0){ans[d[j].pos*-1]-=Sum(d[j].y);}
		else if(d[j].pos>0){ans[d[j].pos]+=Sum(d[j].y);}
		j++;
	//	cout<<num<<endl;
	}
	if(i<=mid)while(i<=mid)q[++num]=d[i],update(d[i].y,d[i].vul),i++;
	if(j<=r){
		while(j<=r){
		q[++num]=d[j];
//		update(d[j].y,d[j].vul);
		if(d[j].pos<0){ans[d[j].pos*-1]-=Sum(d[j].y);}
		else if(d[j].pos>0){ans[d[j].pos]+=Sum(d[j].y);}
		j++;		
	}
}
	for(int k=1;k<=num;k++)d[l+k-1]=q[k],clear(q[k].y);
}
void cdq(int l,int r){
	if(l>=r)return ;
//	cout<<l<<" "<<r<<endl;
	int mid=(l+r)>>1;
	cdq(l,mid);
	cdq(mid+1,r);
	gui(l,mid,r);
	//cout<<l<<"--==="<<r<<endl;
	//for(int i=l;i<=r;i++)cout<<d[i].x<<" "<<d[i].y<<endl;
//	cout<<l<<" "<<r<<endl;
}
int main(){
	int s;s=read();n=read();
	int op;int x,y,x1,y1;
	while(op=read()){
		if(op==3)break;
		if(op==1)d[++cnt].x=read(),d[cnt].y=read(),d[cnt].vul=read(),d[cnt].pos=0,ans[cnt]=-1;
		else{
			x=read();y=read();x1=read();y1=read();
			d[++cnt].x=x-1;d[cnt].y=y-1;d[cnt].pos=cnt;ans[cnt]=1ll*x*y*s;
			int t1=cnt;
			d[++cnt].x=x-1;d[cnt].y=y1;d[cnt].pos=-1*t1;ans[t1]-=1ll*d[cnt].x*d[cnt].y*s;ans[cnt]=-1;
			d[++cnt].x=x1;d[cnt].y=y-1;d[cnt].pos=-1*t1;ans[t1]-=1ll*d[cnt].x*d[cnt].y*s;ans[cnt]=-1;
			d[++cnt].x=x1;d[cnt].y=y1;d[cnt].pos=t1;ans[t1]+=1ll*d[cnt].x*d[cnt].y*s;ans[cnt]=-1;
			//cout<<ans[t1]<<endl;
		}
	}
	//cout<<cnt<<endl;
	cdq(1,cnt);
	for(int i=1;i<=cnt;i++)if(ans[i]>=0)printf("%lld\n",ans[i]);
}

  

1176: [Balkan2007]Mokia

Time Limit: 30 Sec  Memory Limit: 162 MB
Submit: 3265  Solved: 1460
[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范围

posted @ 2018-06-24 23:42  wang9897  阅读(115)  评论(0编辑  收藏  举报