BZOJ1176: [Balkan2007]Mokia

BZOJ1176: [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范围

题解Here!

矩阵上单点修改,区间查询,二维线段树就可以了。

但是w<=2,000,000。

而且我又不会cdq分治/K-D Tree。

所以只能树状数组套Treap。

将询问拆分一下即可。

附代码:

#include<iostream>
#include<algorithm>
#include<cstdio>
#define MAXN 2000010
using namespace std;
int n;
struct node{
	node* son[2];
	int v,w,x,sum;
	node(){
		son[0]=son[1]=NULL;
		w=rand();
		v=sum=x=0;
	}
};
node* root[MAXN];
inline int read(){
	int date=0,w=1;char c=0;
	while(c<'0'||c>'9'){if(c=='-')w=-1;c=getchar();}
	while(c>='0'&&c<='9'){date=date*10+c-'0';c=getchar();}
	return date*w;
}
inline void maintain(node* &u){
	if(u==NULL)return;
	u->sum=u->v;
	if(u->son[0]!=NULL)u->sum+=u->son[0]->sum;
	if(u->son[1]!=NULL)u->sum+=u->son[1]->sum;
}
inline void turn(node* &u,int f){
	node* t=u->son[f^1];
	u->son[f^1]=t->son[f];
	t->son[f]=u;
	maintain(u);
	maintain(t);
	u=t;
}
void insert(node* &u,int x,int v){
	if(u==NULL){
		u=new node;
		u->x=x;
		u->v=u->sum=v;
		return;
	}
	else if(u->x==x){
		u->v+=v;u->sum+=v;
		return;
	}
	int y=u->x<x?1:0;
	insert(u->son[y],x,v);
	if(u->son[y]->w>u->w)turn(u,y^1);
	maintain(u);
}
int query(node* u,int x){
	int s=0;
	while(u!=NULL){
		if(u->x>x)u=u->son[0];
		else{
			if(u->son[0]!=NULL)s+=u->son[0]->sum;
			s+=u->v;
			u=u->son[1];
		}
	}
	return s;
}
inline int lowbit(int x){return x&(-x);}
inline void update(int x,int y,int v){
	for(int i=x;i<=n;i+=lowbit(i))insert(root[i],y,v);
}
inline int sum(int x,int y){
	int s=0;
	for(int i=x;i;i-=lowbit(i))s+=query(root[i],y);
	return s;
}
void work(){
	while(1){
		int f=read();
		if(f==3)break;
		if(f==1){
			int x=read(),y=read(),k=read();
			update(x,y,k);
		}
		else if(f==2){
			int x1=read(),y1=read(),x2=read(),y2=read();
			printf("%d
",sum(x2,y2)-sum(x1-1,y2)-sum(x2,y1-1)+sum(x1-1,y1-1));
		}
	}
}
void init(){
	srand(987);
	int x=read();
	n=read();
}
int main(){
	init();
	work();
	return 0;
}
原文地址:https://www.cnblogs.com/Yangrui-Blog/p/9369067.html