你有一个N*N的棋盘,每个格子内有一个整数,初始时的时候全部为0,现在需要维护两种操作:
命令
|
参数限制
|
内容
|
1 x y A
|
1<=x,y<=N,A是正整数
|
将格子x,y里的数字加上A
|
2 x1 y1 x2 y2
|
1<=x1<= x2<=N
1<=y1<= y2<=N
|
输出x1 y1 x2 y2这个矩形内的数字和
|
3
|
无
|
终止程序
|
输入文件第一行一个正整数N。
接下来每行一个操作。每条命令除第一个数字之外,
均要异或上一次输出的答案last_ans,初始时last_ans=0。
数据规模和约定
1<=N<=500000,操作数不超过200000个,内存限制20M,保证答案在int范围内并且解码之后数据仍合法。
根据kd-tree思想,我们划分二维空间,搞出一颗神奇的二维二叉搜索树(kd-tree的本质),每次插入结点就直接按二叉搜索树的规则插入,查询也是按二叉搜索树的规则来查询。然而注意到这种做法在这道题是可以被卡的,比如说全挂在了一边,退化成链(变态出题人)
1 //It is made by jump~
2 #include <iostream>
3 #include <cstdlib>
4 #include <cstring>
5 #include <cstdio>
6 #include <cmath>
7 #include <algorithm>
8 #include <ctime>
9 #include <vector>
10 #include <queue>
11 #include <map>
12 #ifdef WIN32
13 #define OT "%I64d"
14 #else
15 #define OT "%lld"
16 #endif
17 using namespace std;
18 typedef long long LL;
19 const int MAXN = 200011;
20 const int MOD = 5000;
21 int n,m;
22 int ans;
23 int k1,k2,val;
24 int lx,ly,rx,ry;
25 int root;
26 int nowD;
27
28 struct node{
29 int d[2],Min[2],Max[2];
30 int sum,w;
31 int ch[2];
32 }t[MAXN];
33
34 inline int getint()
35 {
36 int w=0,q=0;
37 char c=getchar();
38 while((c<‘0‘ || c>‘9‘) && c!=‘-‘) c=getchar();
39 if (c==‘-‘) q=1, c=getchar();
40 while (c>=‘0‘ && c<=‘9‘) w=w*10+c-‘0‘, c=getchar();
41 return q ? -w : w;
42 }
43
44 inline void update(int now){
45 t[now].sum=t[now].w;
46 for(int i=0;i<=1;i++) {
47 if(t[now].ch[i]) {
48 t[now].sum+=t[ t[now].ch[i] ].sum;
49 if(t[ t[now].ch[i] ].Min[0] < t[now].Min[0]) t[now].Min[0]=t[ t[now].ch[i] ].Min[0];
50 if(t[ t[now].ch[i] ].Max[0] > t[now].Max[0]) t[now].Max[0]=t[ t[now].ch[i] ].Max[0];
51 if(t[ t[now].ch[i] ].Min[1] < t[now].Min[1]) t[now].Min[1]=t[ t[now].ch[i] ].Min[1];
52 if(t[ t[now].ch[i] ].Max[1] > t[now].Max[1]) t[now].Max[1]=t[ t[now].ch[i] ].Max[1];
53 }
54 }
55 }
56
57 inline void kd_insert(int root,int D){
58 int direc=(t[n].d[D]>t[root].d[D]);
59 if(t[root].ch[direc]) kd_insert(t[root].ch[direc],D^1);
60 else t[root].ch[direc]=n;
61 update(root);
62 }
63
64 inline void kd_query(int now){
65 if(t[now].d[0]>=lx && t[now].d[1]>=ly && t[now].d[0]<=rx && t[now].d[1]<=ry) ans+=t[now].w;
66 for(int i=0;i<=1;i++) {
67 if(t[now].ch[i]){
68 if(t[t[now].ch[i]].Min[0]<=rx&&t[t[now].ch[i]].Max[0]>=lx&&t[t[now].ch[i]].Min[1]<=ry&&t[t[now].ch[i]].Max[1]>=ly) {
69 if(t[t[now].ch[i]].Max[0]<=rx && t[t[now].ch[i]].Min[0]>=lx && t[t[now].ch[i]].Max[1]<=ry && t[t[now].ch[i]].Min[1]>=ly) ans+=t[t[now].ch[i]].sum;
70 else kd_query(t[now].ch[i]);
71 }
72 }
73 }
74 }
75
76 inline bool cmp(node q,node qq){
77 if(q.d[nowD]==qq.d[nowD]) return q.d[nowD^1]<qq.d[nowD^1];
78 return q.d[nowD]<qq.d[nowD];
79 }
80
81 inline int rebuild(int l,int r,int D){
82 int mid=(l+r)/2; nowD=D;
83 nth_element(t+l+1,t+mid+1,t+r+1,cmp);
84 //t[mid].sum=t[mid].w;
85 t[mid].Min[0]=t[mid].Max[0]=t[mid].d[0]; t[mid].Min[1]=t[mid].Max[1]=t[mid].d[1];
86 if(l!=mid) t[mid].ch[0]=rebuild(l,mid-1,D^1);
87 if(mid!=r) t[mid].ch[1]=rebuild(mid+1,r,D^1);
88 update(mid);
89 return mid;
90 }
91
92 inline void solve(){
93 int ljh; root=1;
94 while(1){
95 ljh=getint();
96 if(ljh==3) break;
97 else if(ljh==1) {
98 k1=getint();k2=getint();val=getint();
99 k1=k1^ans; k2=k2^ans; val=val^ans;
100 n++; t[n].Min[0]=t[n].Max[0]=t[n].d[0]=k1; t[n].Min[1]=t[n].Max[1]=t[n].d[1]=k2; t[n].w=t[n].sum=val;
101 if(n>1){
102 if(n%MOD==0) {
103 for(int i=1;i<=n;i++) t[i].ch[0]=t[i].ch[1]=0;
104 root=rebuild(1,n,0);
105 }
106 else
107 kd_insert(root,0);
108 }
109 }
110 else {
111 lx=getint();ly=getint();rx=getint();ry=getint();
112 lx=lx^ans; ly=ly^ans; rx=rx^ans; ry=ry^ans;
113 ans=0;
114 if(n)
115 kd_query(root);
116 printf("%d\n",ans);
117 }
118 }
119 }
120
121 int main()
122 {
123 m=getint(); solve();
124 return 0;
125 }