题意:你有一个\(N \times N\)的棋盘,每个格子内有一个整数,初始时的时候全部为 \(0\),现在需要维护两种操作:
- 1 x y A
\(1\le x,y\le N\),\(A\) 是正整数。将格子x
,y
里的数字加上 \(A\)。
- 2 x1 y1 x2 y2
\(1 \le x_1 \le x_2 \le N\),\(1 \le y_1\le y_2 \le N\)。输出 \(x_1, y_1, x_2, y_2\) 这个矩形内的数字和
- 3
无 终止程序
首先KD-Tree的理论很好理解,就是将一棵树按照某一维度划分成左右子树,然后继续递归分别处理左右子树,选择一个合适的维度作为划分方法,保证树的深度为\(logn\)。上方链接中还提到了本题需要用到的树重构,因为本题操作1相当于在树中新增节点,这样会改变树的结构,可能导致其不平衡,所以设置一个平衡条件来判断当前树是否需要重构。
#include<bits/stdc++.h>
using namespace std;
#define ll long long
inline int read(){
int x=0,o=1;char ch=getchar();
while(ch!='-'&&(ch<'0'||ch>'9'))ch=getchar();
if(ch=='-')o=-1,ch=getchar();
while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
return x*o;
}
const int N=5e5+5;
const int M=2e4+5;
const int mod=1e9+7;
int n,lastans,tot,rt,t;
int l[N],r[N],d[N],u[N],ls[N],rs[N];
int sum[N],divi[N],size[N],g[N];
struct node{
int x,y,val;
}a[N];
void update(int p){
sum[p]=sum[ls[p]]+sum[rs[p]]+a[p].val;
size[p]=size[ls[p]]+size[rs[p]]+1;
l[p]=r[p]=a[p].x;d[p]=u[p]=a[p].y;
if(ls[p]){
l[p]=min(l[p],l[ls[p]]);r[p]=max(r[p],r[ls[p]]);
d[p]=min(d[p],d[ls[p]]);u[p]=max(u[p],u[ls[p]]);
}
if(rs[p]){
l[p]=min(l[p],l[rs[p]]);r[p]=max(r[p],r[rs[p]]);
d[p]=min(d[p],d[rs[p]]);u[p]=max(u[p],u[rs[p]]);
}
}
bool check(int p){
double zuo=size[ls[p]]*1.0,you=size[rs[p]]*1.0;
double lim=0.725*size[p];
if(zuo>=lim||you>=lim)return true;
return false;
}
void print(int p){
if(!p)return;
print(ls[p]);
g[++t]=p;
print(rs[p]);
}
bool cmp1(int x,int y){
return a[x].x<a[y].x;
}
bool cmp2(int x,int y){
return a[x].y<a[y].y;
}
int build(int l,int r){
if(l>r)return 0;
int mid=(l+r)>>1;
double avx=0,avy=0,fcx=0,fcy=0;
for(int i=l;i<=r;++i){
avx+=a[g[i]].x;avy+=a[g[i]].y;
}
avx=avx*1.0/(r-l+1);avy=avy*1.0/(r-l+1);
for(int i=l;i<=r;++i){
fcx+=(avx-a[g[i]].x)*(avx-a[g[i]].x);
fcy+=(avy-a[g[i]].y)*(avy-a[g[i]].y);
}
if(fcx>=fcy){
nth_element(g+l,g+mid,g+r+1,cmp1);
divi[g[mid]]=1;
}
else{
nth_element(g+l,g+mid,g+r+1,cmp2);
divi[g[mid]]=2;
}
ls[g[mid]]=build(l,mid-1);
rs[g[mid]]=build(mid+1,r);
update(g[mid]);
return g[mid];
}
void rebuild(int& p){
t=0;
print(p);
p=build(1,t);
}
void insert(int& p,int cur){
if(!p){
p=cur;
update(p);
return;
}
if(divi[p]==1){
if(a[cur].x<=a[p].x)insert(ls[p],cur);
else insert(rs[p],cur);
}
else{
if(a[cur].y<=a[p].y)insert(ls[p],cur);
else insert(rs[p],cur);
}
update(p);
if(check(p))rebuild(p);
}
int query(int p,int x1,int y1,int x2,int y2){
if(!p||x2<l[p]||x1>r[p]||y2<d[p]||y1>u[p])return 0;
if(l[p]>=x1&&r[p]<=x2&&d[p]>=y1&&u[p]<=y2)return sum[p];
int cnt=0;
if(a[p].x>=x1&&a[p].x<=x2&&a[p].y>=y1&&a[p].y<=y2)cnt+=a[p].val;
return query(ls[p],x1,y1,x2,y2)+query(rs[p],x1,y1,x2,y2)+cnt;
}
int main() {
n=read();
while(1){
int opt=read();
if(opt==1){
int x=read(),y=read(),val=read();
x^=lastans;y^=lastans;val^=lastans;
a[++tot].x=x;a[tot].y=y;a[tot].val=val;
insert(rt,tot);
}
else if(opt==2){
int x1=read(),y1=read(),x2=read(),y2=read();
x1^=lastans;y1^=lastans;x2^=lastans;y2^=lastans;
lastans=query(rt,x1,y1,x2,y2);
cout<<lastans<<endl;
}
else break;
}
return 0;
}