题目大意:
给定一个 n∗n n ∗ n ( n≤1e5) n ≤ 1 e 5 ) 的矩阵,单点修改,区间查询。
思路:
二维树状数组?空间开不下。
那就换一个办法,记得之前用cdq分治来做树状数组的时候,每一个查询的答案是在它前面的修改的并且修改的位置在它前面的才可以计入答案,这里也是一样,将每一个询问拆成四个前缀和数组之后,每一个查询的答案为在它前面修改的并且
x
x
小于它也小于它的值的和,这就是一个三维偏序。二维树状数组的复杂度是
nlog2n
n
log
2
n
,cdq分治的时间复杂度也是
nlog2n
n
log
2
n
。
/*=======================
* Author : ylsoi
* Problem : bzoj2683
* Algorithm : cdq
* Time : 2018.7.30
* ====================*/
#include<bits/stdc++.h>
#define REP(i,a,b) for(int i=a;i<=b;++i)
#define mid ((l+r)>>1)
typedef long long ll;
using namespace std;
void File(){
freopen("bzoj2683.in","r",stdin);
freopen("bzoj2683.out","w",stdout);
}
const int maxn=5e5+10;
const int maxm=2e5+10;
int n,m,sum[maxn];
struct node{
int id,x,y,val;
bool ty;
}a[maxm<<2],tmp[maxm<<2];
bool cmp(node xx,node yy){return xx.id<yy.id;}
int lowbit(int x){return x&(-x);}
void modify(int pos,int x){
while(pos<=n){
sum[pos]+=x;
pos+=lowbit(pos);
}
}
int query(int pos){
int ret=0;
while(pos>=1){
ret+=sum[pos];
pos-=lowbit(pos);
}
return ret;
}
void cdq(int l,int r){
if(l==r)return;
cdq(l,mid); cdq(mid+1,r);
int p=l,pl=l,pr=mid+1;
while(pl<=mid && pr<=r){
if(a[pl].x<=a[pr].x){
if(!a[pl].ty)modify(a[pl].y,a[pl].val);
tmp[p++]=a[pl++];
}
else{
if(a[pr].ty)a[pr].val+=query(a[pr].y);
tmp[p++]=a[pr++];
}
}
if(pl<=mid){
REP(i,l,pl-1)if(!a[i].ty)modify(a[i].y,-a[i].val);
while(pl<=mid)tmp[p++]=a[pl++];
}
else{
while(pr<=r){
if(a[pr].ty)a[pr].val+=query(a[pr].y);
tmp[p++]=a[pr++];
}
REP(i,l,mid)if(!a[i].ty)modify(a[i].y,-a[i].val);
}
REP(i,l,r)a[i]=tmp[i];
}
void init(){
scanf("%d",&n);
int ty,x0,y0,x2,y2,val;
while(~scanf("%d",&ty)){
if(ty==3)break;
if(ty==1){
scanf("%d%d%d",&x0,&y0,&val);
a[++m]=(node){m,x0,y0,val,0};
}
else{
scanf("%d%d%d%d",&x0,&y0,&x2,&y2);
a[++m]=(node){m,x2,y2,0,1};
a[++m]=(node){m,x2,y0-1,0,1};
a[++m]=(node){m,x0-1,y2,0,1};
a[++m]=(node){m,x0-1,y0-1,0,1};
}
}
}
int main(){
File();
init();
cdq(1,m);
sort(a+1,a+m+1,cmp);
REP(i,1,m)if(a[i].ty){
printf("%d\n",a[i].val-a[i+1].val-a[i+2].val+a[i+3].val);
i+=3;
}
return 0;
}