题目
你有一个N \times NN×N的棋盘,每个格子内有一个整数,初始时的时候全部为0,现在需要维护两种操作:
1 x y A 1\le x,y\le N1≤x,y≤N,A是正整数。将格子x,y里的数字加上AA
2 x1 y1 x2 y2 1 \le x_1 \le x_2 \le N1≤x
1
≤x
2
≤N,1 \le y_1\le y_2 \le N1≤y
1
≤y
2
≤N。输出x_1, y_1, x_2, y_2x
1
,y
1
,x
2
,y
2
这个矩形内的数字和
3 无 终止程序
输入格式
输入文件第一行一个正整数N。
接下来每行一个操作。每条命令除第一个数字之外,均要异或上一次输出的答案last_ans,初始时last_ans=0。
输出格式
对于每个2操作,输出一个对应的答案。
输入输出样例
输入 #1 复制
4
1 2 3 3
2 1 1 3 3
1 1 1 1
2 1 1 0 7
3
输出 #1 复制
3
5
说明/提示
1<=N<=500000,操作数不超过200000个,内存限制20M,保证答案在int范围内并且解码之后数据仍合法。
思路
KD-tree模板题
把每个插入操作看成一个点
如果插入导致不平衡,就像替罪羊树那样拍扁重构。
每个节点记录子树内横纵坐标的最大值
查询就比较显然了
代码
#include<bits/stdc++.h>
using namespace std;
int read() {
int q=0,w=1;char ch=' ';
while(ch!='-'&&(ch<'0'||ch>'9')) ch=getchar();
if(ch=='-') w=-1,ch=getchar();
while(ch>='0'&&ch<='9') q=q*10+ch-'0',ch=getchar();
return q*w;
}
const int N=200005;
struct yjy{int x[2],w;}p[N];
struct node{int mi[2],mx[2],sum,ls,rs,sz;yjy tp;}tr[N];
int n,ans,rt,WD,top,cur,rub[N];
int operator < (yjy a,yjy b) {return a.x[WD]<b.x[WD];}
int newnode() {
if(top) return rub[top--];
else return ++cur;
}
void up(int k) {
int l=tr[k].ls,r=tr[k].rs;
for(int i=0;i<=1;++i) {
tr[k].mi[i]=tr[k].mx[i]=tr[k].tp.x[i];
if(l) tr[k].mi[i]=mcheck_1(tr[k].mi[i],tr[l].mi[i]);
if(r) tr[k].mi[i]=mcheck_1(tr[k].mi[i],tr[r].mi[i]);
if(l) tr[k].mx[i]=max(tr[k].mx[i],tr[l].mx[i]);
if(r) tr[k].mx[i]=max(tr[k].mx[i],tr[r].mx[i]);
}
tr[k].sum=tr[l].sum+tr[r].sum+tr[k].tp.w,tr[k].sz=tr[l].sz+tr[r].sz+1;
}
int build(int l,int r,int wd) {
if(l>r) return 0;
int mid=(l+r)>>1,k=newnode();
WD=wd,nth_element(p+l,p+mid,p+r+1),tr[k].tp=p[mid];
tr[k].ls=build(l,mid-1,wd^1),tr[k].rs=build(mid+1,r,wd^1);
up(k);return k;
}
void pia(int k,int num) {
if(tr[k].ls) pia(tr[k].ls,num);
p[tr[tr[k].ls].sz+num+1]=tr[k].tp,rub[++top]=k;
if(tr[k].rs) pia(tr[k].rs,num+tr[tr[k].ls].sz+1);
}
void check(int &k,int wd) {
if(tr[k].sz*0.75<tr[tr[k].ls].sz||tr[k].sz*0.75<tr[tr[k].rs].sz)
pia(k,0),k=build(1,tr[k].sz,wd);
}
void ins(int &k,yjy tmp,int wd) {
if(!k) {k=newnode(),tr[k].ls=tr[k].rs=0,tr[k].tp=tmp,up(k);return;}
if(tmp.x[wd]<=tr[k].tp.x[wd]) ins(tr[k].ls,tmp,wd^1);
else ins(tr[k].rs,tmp,wd^1);
up(k),check(k,wd);
}
int check_1(int x1,int y1,int x2,int y2,int X1,int Y1,int X2,int Y2) {
return (X1>=x1&&X2<=x2&&Y1>=y1&&Y2<=y2);
}
int check_2(int x1,int y1,int x2,int y2,int X1,int Y1,int X2,int Y2) {
return (x1>X2||x2<X1||y1>Y2||y2<Y1);
}
int query(int k,int x1,int y1,int x2,int y2) {
if(!k) return 0;
int re=0;
if(check_1(x1,y1,x2,y2,tr[k].mi[0],tr[k].mi[1],tr[k].mx[0],tr[k].mx[1])) return tr[k].sum;
if(check_2(x1,y1,x2,y2,tr[k].mi[0],tr[k].mi[1],tr[k].mx[0],tr[k].mx[1])) return 0;
if(check_1(x1,y1,x2,y2,tr[k].tp.x[0],tr[k].tp.x[1],tr[k].tp.x[0],tr[k].tp.x[1]))
re+=tr[k].tp.w;
re+=query(tr[k].ls,x1,y1,x2,y2)+query(tr[k].rs,x1,y1,x2,y2);
return re;
}
int main()
{
int bj,x1,y1,x2,y2;
n=read();
while(1)
{
bj=read(); if(bj==3) break;
if(bj==1) ins(rt,(yjy){read()^ans,read()^ans,read()^ans},0);
else
{
x1=read()^ans,y1=read()^ans,x2=read()^ans,y2=read()^ans;
ans=query(rt,x1,y1,x2,y2),printf("%d\n",ans);
}
}
return 0;
}