去年区域赛留下来的遗憾题之一。

此题要考的是坐标转换后的二维树状数组,难点在于内存开不下,需要20000**20000,现场赛胆大的直接开了这么大就过了,向我们这种胆小的就直接被吓傻了。

hdu上内存32768K。

由树状数组的性质可知每次最多只会更新log(n)次,因此二维树状数组总共会更新m log(n)log(n)个地方,所以想办法存这些值就可以了,map会超时,搞个靠谱点的hash就可以了。

另一种解法估计就是出题人想考的,第一维照样用树状数组,第二维再套个平衡树来维护在这个范围内的区间和。

第二种解法代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
#include <stdio.h>
#include <math.h>
#include <algorithm>
#include <iostream>
#include <vector>
#include <queue>
#include <bitset>
#include <string.h>
#include <map>
#include <set>
#define ll long long
#define clr(a,b) memset(a,b,sizeof(a))
#define sqr(x) ((x)*(x))
using namespace std;
const double eps=1e-8;

int n,m;
const int N = 2000000;

int key[N],sz[N],lc[N],rc[N],w[N],sum[N];
int num;


void newnode(int i)
{
key[i] = sz[i] = lc[i] = rc[i] = w[i] = sum[i] = 0;
}
class sbtree
{
public:
int root;
void clear()
{
newnode(++num);
root = num;
sz[root] = 1;
}
void Insert(int &root,int val,int ww)
{
if (root == 0)
{
root = ++num;
lc[root] = rc[root] = 0;
sz[root] = 1;
key[root] = val;
w[root] = ww;
sum[root] = ww;
return ;
}
sum[root] += ww;
sz[root] ++;
if (val < key[root])
{
Insert(lc[root] , val , ww);
}
else
{
Insert(rc[root] , val , ww);
}
maintain(root , !(val < key[root]));
}

int query(int val){
int tmp = root;
int ans = 0;
while(tmp){
if(key[tmp] <= val){
ans += sum[lc[tmp]] + w[tmp];
tmp = rc[tmp];
}
else{
tmp = lc[tmp];
}
}
return ans;
}

void LeftRotate(int &root)
{
int temp = rc[root];
rc[root] = lc[temp];
lc[temp] = root;
sz[temp] = sz[root];
sum[temp] = sum[root];
sz[root] = 1 + sz[lc[root]] + sz[rc[root]];
sum[root] = sum[lc[root]] + sum[rc[root]] + w[root];
root = temp;
}
void RightRotate(int &root)
{
int temp = lc[root];
lc[root] = rc[temp];
rc[temp] = root;
sz[temp] = sz[root];
sum[temp] = sum[root];
sz[root] = 1 + sz[lc[root]] + sz[rc[root]];
sum[root] = sum[lc[root]] + sum[rc[root]] + w[root];
root = temp;
}
void maintain(int &root , bool flag)
{
if (root == 0) return ;
if ( !flag ) // 调整左子树
{
if ( sz[lc[lc[root]]] > sz[rc[root]] )
{
RightRotate( root );
}
else if ( sz[rc[lc[root]]] > sz[rc[root]] )
{
LeftRotate( lc[root] );
RightRotate( root );
}
else
{
return ;
}
}
else // 调整右子树
{
if ( sz[rc[rc[root]]] > sz[lc[root]] )
{
LeftRotate( root );
}
else if ( sz[lc[rc[root]]] > sz[lc[root]] )
{
RightRotate( rc[root] );
LeftRotate( root );
}
else
{
return ;
}
}
maintain(lc[root] , false);
maintain(rc[root] , true);
maintain(root , false);
maintain(root , true);
}

} sbt[30000];



int lb(int x)
{
return x&(-x);
}
void ch(int &x,int &y)
{
int nx = n+x-y;
int ny = x+y-1;
x = nx;
y = ny;
}
void initval()
{
num = 0;
for(int i=1; i<=2*n; i++)
sbt[i].clear();
}


void add(int x,int y,int z)
{
for(int i=x; i<=2*n; i+=lb(i))
sbt[i].Insert(sbt[i].root,y,z);
}
int get(int x,int y1,int y2)
{
int ans = 0;
for(int i=x; i>0; i-=lb(i))
ans += sbt[i].query(y2) - sbt[i].query(y1);
return ans;
}
int main()
{
// freopen("/home/zyc/Documents/Code/cpp/in","r",stdin);
while(1)
{
scanf("%d",&n);
if(n==0) return 0;
scanf("%d",&m);
initval();
while(m--)
{
int type,x,y,z;
scanf("%d%d%d%d",&type,&x,&y,&z);
if(type==1)
{
ch(x,y);
add(x,y,z);
}
else
{
int a,b,c,d;
a = x - z;
b = y;
c = x + z;
d = y;
ch(a,b);
ch(c,d);

a = max(1,a);
c = min(2*n,c);

a--;
b--;
printf("%d\n",get(c,b,d) - get(a,b,d) );
}
}
}
return 0;
}