题目
题目描述
原题
核能国可以看作一个由
W
×
H
W \times H
W×H的方格组成的矩形。核能国有
N
N
N个核电站,每个核电站占用一个方格。不幸的是,核能国遭遇了百年一遇的特大地震,导致所有的核电站都发生了核泄漏。
每个核电站的核泄漏程度可以用两个整数
a
,
b
a, b
a,b来表示。如果位于
P
=
[
x
P
,
y
P
]
P=[x_P,y_P]
P=[xP,yP]的核电站爆炸,方格
C
=
[
x
C
,
y
C
]
C=[x_C,y_C]
C=[xC,yC]会增加
m
a
x
(
0
,
a
−
b
×
d
(
P
,
C
)
)
\mathrm{max}(0,a-b\times d(P,C))
max(0,a−b×d(P,C))贝克的辐射(贝克是单位),其中
d
(
P
,
C
)
d(P,C)
d(P,C)是两个方格的切比雪夫距离,即
d
(
P
,
C
)
=
m
a
x
(
∣
x
P
−
x
C
∣
,
∣
y
P
−
y
C
∣
)
d(P,C) =\mathrm{max}(|x_P - x_C|,|y_P - y_C|)
d(P,C)=max(∣xP−xC∣,∣yP−yC∣)。
一个方格可能会受到多处核泄漏的影响。
例如,如果一个
a
=
7
,
b
=
3
a = 7, b = 3
a=7,b=3的核电站爆炸了,所在的方格
X
X
X会受到
7
7
7贝克辐射(贝克是单位),满足
d
(
X
,
Y
)
=
1
d(X,Y) = 1
d(X,Y)=1的
8
8
8个方格
Y
Y
Y会受到
4
4
4贝克辐射,满足
d
(
X
,
Z
)
=
2
d(X,Z) = 2
d(X,Z)=2的
16
16
16个方格
Z
Z
Z会受到
1
1
1贝克辐射。
环保部门给了你
Q
Q
Q组询问,每组询问会划定核能国领土中的一个矩形,请回答:矩形区域内(每个方格)所受的平均辐射量为多少。
输入格式
第一行,两个正整数
W
W
W和
H
(
W
×
H
⩽
2.5
×
1
0
6
)
H(W × H \leqslant 2.5×10^6)
H(W×H⩽2.5×106),分别表示核能国的宽度与高度。
第二行,一个正整数
N
N
N,表示核电站的个数
(
1
≤
N
⩽
2
×
1
0
5
)
(1 \leq N \leqslant 2×10^5)
(1≤N⩽2×105)。
在接下来的
N
N
N行中,每行四个正整数
x
i
,
y
i
,
a
i
,
b
i
(
1
⩽
x
i
⩽
W
,
1
⩽
y
i
⩽
H
,
1
⩽
a
i
,
b
i
⩽
1
0
9
)
x_i,y_i,a_i,b_i(1 \leqslant x_i \leqslant W,1 \leqslant y_i \leqslant H,1 \leqslant a_i,b_i \leqslant 10^9)
xi,yi,ai,bi(1⩽xi⩽W,1⩽yi⩽H,1⩽ai,bi⩽109),表示有一个核电站位于方格
[
x
i
,
y
i
]
[x_i,y_i]
[xi,yi],它的参数为
a
i
a_i
ai与
b
i
b_i
bi。每个格子最多有一个核电站。
第
N
+
3
N+3
N+3行,一个正整数
Q
Q
Q,表示询问的次数
(
1
≤
Q
≤
2
×
1
0
5
)
(1 \leq Q \leq 2×10^5)
(1≤Q≤2×105)。
在接下来的
Q
Q
Q行中,每行四个 正整数
x
1
j
,
y
1
j
,
x
2
j
,
y
2
j
(
1
⩽
x
1
j
⩽
x
2
j
⩽
W
,
1
⩽
y
1
j
⩽
y
2
j
⩽
H
)
x_{1j},y_{1j},x_{2j},y_{2j}(1 \leqslant x_{1j} \leqslant x_{2j} \leqslant W,1 \leqslant y_{1j} \leqslant y_{2j} \leqslant H)
x1j,y1j,x2j,y2j(1⩽x1j⩽x2j⩽W,1⩽y1j⩽y2j⩽H),表示该询问给出的矩形区域的左上角在
[
x
1
j
,
y
1
j
]
[x_{1j},y_{1j}]
[x1j,y1j]且它的右下角在
[
x
2
j
,
y
2
j
]
[x_{2j},y_{2j}]
[x2j,y2j]。
你可以假设核能国内的总辐射量少于
2
63
2^{63}
263。
输出格式
对于每个询问,输出一行表示给定矩形区域内所有方格的平均辐射量,四舍五入至整数。
样例
样例输入
4 3
2
1 1 7 3
3 2 4 2
4
1 2 2 3
1 1 4 3
4 2 4 2
1 3 4 3
样例输出
4
4
2
2
样例解释
以下为两次爆炸后对每个方格产生的辐射量:
7 6 3 2
4 6 5 2
1 3 3 2
- 2 2 2^2 22方形区域内的总辐射为 14 14 14,所以平均值为 14 ÷ 4 = 3.5 14\div 4=3.5 14÷4=3.5,四舍五入至 4 4 4。
- 整个核能国的总辐射为 44 44 44,所以平均值为 44 ÷ 12 ≈ 3.67 44\div 12 \approx 3.67 44÷12≈3.67,四舍五入至 4 4 4。
- 单个格子的平均辐射量就是它所受到的辐射量。
- 最后一行的平均辐射量为 9 ÷ 4 = 2.25 9\div 4=2.25 9÷4=2.25,四舍五入至 2 2 2。
数据范围与提示
有 14 14 14组测试数据。奇数的测试组只包含 a a a是 b b b的倍数的核电站。对每个子任务的进一步限制如下:
测试组 | 进一步限制 | 分数 |
---|---|---|
1 | H = 1 , N ⋅ W ⩽ 1 0 8 , Q ⋅ W ⩽ 1 0 8 H=1,N\cdot W \leqslant 10^8,Q \cdot W \leqslant 10^8 H=1,N⋅W⩽108,Q⋅W⩽108 | 3 |
2 | H = 1 , N ⋅ W ⩽ 1 0 8 , Q ⋅ W ⩽ 1 0 8 H=1,N\cdot W \leqslant 10^8,Q \cdot W \leqslant 10^8 H=1,N⋅W⩽108,Q⋅W⩽108 | 2 |
3 | N ⋅ W ⋅ H ≤ 1 0 8 , Q ⋅ W ⋅ H ≤ 1 0 8 N\cdot W \cdot H \leq 10^8,Q \cdot W \cdot H \leq 10^8 N⋅W⋅H≤108,Q⋅W⋅H≤108 | 3 |
4 | N ⋅ W ⋅ H ≤ 1 0 8 , Q ⋅ W ⋅ H ≤ 1 0 8 N\cdot W \cdot H \leq 10^8,Q \cdot W \cdot H \leq 10^8 N⋅W⋅H≤108,Q⋅W⋅H≤108 | 2 |
5 | H = 1 , N ⋅ W ≤ 1 0 8 H=1,N\cdot W \leq 10^8 H=1,N⋅W≤108 | 6 |
6 | H = 1 , N ⋅ W ≤ 1 0 8 H=1,N\cdot W \leq 10^8 H=1,N⋅W≤108 | 4 |
7 | N ⋅ W ⋅ H ≤ 1 0 8 N\cdot W \cdot H \leq 10^8 N⋅W⋅H≤108 | 6 |
8 | N ⋅ W ⋅ H ≤ 1 0 8 N\cdot W \cdot H \leq 10^8 N⋅W⋅H≤108 | 4 |
9 | H = 1 H=1 H=1 | 15 |
10 | H = 1 H=1 H=1 | 10 |
11 | 没有符合界限定义的爆炸事件 | 15 |
12 | 没有符合界限定义的爆炸事件 | 10 |
13 | 无 | 12 |
14 | 无 | 8 |
如果核电站位于核能国的边境或是在离边境稍近的位置,那么爆炸可能也会影响到核能国之外的方格。影响到核能国外方格的爆炸被称作界限。
题解
暴力算法1
最暴力的算法你能想到什么?枚举!
对于每个核电站爆炸事件,枚举它周围的方格受到的影响
直接枚举整个国度显得太暴力了,我们能不能稍稍优化一下呢?
显然是可以的
我们发现,每个核电站爆炸事件有一个“势力范围”
只有在这个方格和核电站的切比雪夫距离
⩽
a
b
\leqslant\frac{a}{b}
⩽ba时,它才会受影响
所以,我们只需要枚举这个核电站的势力范围就可以了
//官方程序
#include <stdio.h>
#include <stdlib.h>
#define MAXWH 10000000
#define MAXN 1000000
#define MAXQ 1000000
typedef long long int huge;
int w, h, n, q;
typedef struct NUCLEARIA
{
huge Info[MAXWH];
huge& operator () (int x, int y) {return Info[(y * w) + x];}//其实就是个二维数组
}
NUCLEARIA;
typedef struct PLANT
{
int x;
int y;
int a;
int b;
}
PLANT;
typedef struct QUERY
{
int x1;
int y1;
int x2;
int y2;
}
QUERY;
NUCLEARIA Nuclearia;
PLANT Plant[MAXN];
QUERY Query[MAXQ];
int min(int a, int b)
{
return (a < b) ? a : b;
}
int max(int a, int b)
{
return (a > b) ? a : b;
}
int abs(int a)
{
return (a < 0) ? -a : a;
}
int dist(int x1, int y1, int x2, int y2)
{
return max(abs(x1 - x2), abs(y1 - y2));
}
void Print(huge sum, int area)//四舍五入
{
huge rsl = sum / area;
if((sum % area) * 2 >= area)
{
rsl++;
}
printf("%lld\n", rsl);
}
int main()
{
scanf("%d%d", &w, &h);
scanf("%d", &n);
for(int i = 0; i < n; i++)
{
scanf("%d%d%d%d", &(Plant[i].x), &(Plant[i].y), &(Plant[i].a), &(Plant[i].b));
Plant[i].x--;
Plant[i].y--;
}
scanf("%d", &q);
for(int i = 0; i < q; i++)
{
scanf("%d%d%d%d", &(Query[i].x1), &(Query[i].y1), &(Query[i].x2), &(Query[i].y2));
Query[i].x1--;
Query[i].y1--;
}
for(int i = 0; i < n; i++)
{
PLANT& P = Plant[i];
int d = (P.a - 1) / P.b;
int x1 = max(0, P.x - d);
int y1 = max(0, P.y - d);
int x2 = min(w, P.x + d + 1);
int y2 = min(h, P.y + d + 1);
//势力范围
for(int x = x1; x < x2; x++)
{
for(int y = y1; y < y2; y++)
{
int d = dist(x, y, P.x, P.y);
Nuclearia(x, y) += P.a - (d * P.b);
}
}
}
for(int i = 0; i < q; i++)
{
QUERY& Q = Query[i];
huge rsl = 0;
for(int x = Q.x1; x < Q.x2; x++)
{
for(int y = Q.y1; y < Q.y2; y++)
{
rsl += Nuclearia(x, y);
}
}
Print(rsl, (Q.x2 - Q.x1) * (Q.y2 - Q.y1));
}
return 0;
}
暴力算法2
我们发现上面的算法在询问次数很多时是很耗时间的,因为每次我们都需要把矩形的辐射量加一遍
所以,我们可以在询问前先预处理一下
大家应该知道激光炸弹吧?我们可以借用一下这种矩阵的预处理方法,就是计算出左上角在
[
1
,
1
]
[1,1]
[1,1]且它的右下角在
[
x
,
y
]
[x,y]
[x,y]的矩形的总辐射,假设是
N
u
c
l
e
a
r
i
a
(
x
,
y
)
Nuclearia(x,y)
Nuclearia(x,y)
最终的答案就是
N
u
c
l
e
a
r
i
a
(
x
2
j
,
y
2
j
)
−
N
u
c
l
e
a
r
i
a
(
x
1
j
−
1
,
y
2
j
)
−
N
u
c
l
e
a
r
i
a
(
x
2
j
,
y
1
j
−
1
)
+
N
u
c
l
e
a
r
i
a
(
x
1
j
−
1
,
y
1
j
−
1
)
Nuclearia(x_{2j},y_{2j})-Nuclearia(x_{1j}-1,y_{2j})-Nuclearia(x_{2j},y_{1j}-1)+Nuclearia(x_{1j}-1,y_{1j}-1)
Nuclearia(x2j,y2j)−Nuclearia(x1j−1,y2j)−Nuclearia(x2j,y1j−1)+Nuclearia(x1j−1,y1j−1)
//官方程序
#include <stdio.h>
#include <stdlib.h>
#define MAXWH 10000000
#define MAXN 1000000
#define MAXQ 1000000
typedef long long int huge;
int w, h, n, q;
typedef struct NUCLEARIA
{
huge Info[MAXWH];
huge& operator () (int x, int y) {return Info[(y * w) + x];}//其实就是个二维数组
}
NUCLEARIA;
typedef struct PLANT
{
int x;
int y;
int a;
int b;
}
PLANT;
typedef struct QUERY
{
int x1;
int y1;
int x2;
int y2;
}
QUERY;
NUCLEARIA Nuclearia;
PLANT Plant[MAXN];
QUERY Query[MAXQ];
int min(int a, int b)
{
return (a < b) ? a : b;
}
int max(int a, int b)
{
return (a > b) ? a : b;
}
int abs(int a)
{
return (a < 0) ? -a : a;
}
int dist(int x1, int y1, int x2, int y2)
{
return max(abs(x1 - x2), abs(y1 - y2));
}
void Summarize()//预处理
{
for(int x = 0; x < w; x++)
{
for(int y = 0; y < h; y++)
{
if(x) Nuclearia(x, y) += Nuclearia(x - 1, y);
if(y) Nuclearia(x, y) += Nuclearia(x, y - 1);
if((x) && (y)) Nuclearia(x, y) -= Nuclearia(x - 1, y - 1);
}
}
}
void Print(huge sum, int area)//四舍五入
{
huge rsl = sum / area;
if((sum % area) * 2 >= area)
{
rsl++;
}
printf("%lld\n", rsl);
}
int main()
{
scanf("%d%d", &w, &h);
scanf("%d", &n);
for(int i = 0; i < n; i++)
{
scanf("%d%d%d%d", &(Plant[i].x), &(Plant[i].y), &(Plant[i].a), &(Plant[i].b));
Plant[i].x--;
Plant[i].y--;
}
scanf("%d", &q);
for(int i = 0; i < q; i++)
{
scanf("%d%d%d%d", &(Query[i].x1), &(Query[i].y1), &(Query[i].x2), &(Query[i].y2));
Query[i].x1 -= 2;
Query[i].y1 -= 2;
Query[i].x2--;
Query[i].y2--;
}
for(int i = 0; i < n; i++)
{
PLANT& P = Plant[i];
int d = (P.a - 1) / P.b;
int x1 = max(0, P.x - d);
int y1 = max(0, P.y - d);
int x2 = min(w, P.x + d + 1);
int y2 = min(h, P.y + d + 1);
//势力范围
for(int x = x1; x < x2; x++)
{
for(int y = y1; y < y2; y++)
{
int d = dist(x, y, P.x, P.y);
Nuclearia(x, y) += P.a - (d * P.b);
}
}
}
Summarize();
for(int i = 0; i < q; i++)
{
QUERY& Q = Query[i];
huge rsl = Nuclearia(Q.x2, Q.y2);
if(Q.x1 >= 0) rsl -= Nuclearia(Q.x1, Q.y2);
if(Q.y1 >= 0) rsl -= Nuclearia(Q.x2, Q.y1);
if((Q.x1 >= 0) && (Q.y1 >= 0)) rsl += Nuclearia(Q.x1, Q.y1);
Print(rsl, (Q.x2 - Q.x1) * (Q.y2 - Q.y1));
}
return 0;
}
正解
接着,我们尝试在进一步的优化
回想一下我们在利用树状数组做区间修改时的方法:把区间的前面标记为
+
a
+a
+a,最后面标记为
−
a
-a
−a,这样,就可以进行区间修改了
我们可以借用一下这个思路,来标记一次核电站爆炸事件
首先,我们先找出这个核电站爆炸事件的“势力范围”,接着,把“势力范围”的左上角和右下角标记为
+
a
%
b
+a\% b
+a%b,把左下角和右上角标记为
−
a
%
b
-a\% b
−a%b
然后,我们开两个数组,在这个“势力范围”的对角线上(两条对角线,所以要两个数组)存储
b
b
b的值,为了节省时间,我们可以只在4个角上标记,最后再把对角线上的数全部加出来
因为每个核电站爆炸事件的影响相等方格的,都会围成一个正方形(因为取的是切比雪夫距离),也就是说,我们在统计时,只需要先把对角线上的数复制到
N
u
c
l
e
a
r
i
a
Nuclearia
Nuclearia数组中,再把左边的和上面的数相加再减去左上的数就可以了
看起来有点抽象,我们可以再总结一下:
- 对于每个核电站爆炸事件,计算出它的“势力范围”,左上角为 ( x 1 , y 1 ) (x1,y1) (x1,y1),右下角为 ( x 2 , y 2 ) (x2,y2) (x2,y2)
- 标记: N u c l e a r i a ( x 1 , y 1 ) = N u c l e a r i a ( x 2 , y 2 ) = a % b Nuclearia(x1,y1) = Nuclearia(x2,y2) = a\% b Nuclearia(x1,y1)=Nuclearia(x2,y2)=a%b, N u c l e a r i a ( x 1 , y 2 ) = N u c l e a r i a ( x 2 , y 1 ) = a % b Nuclearia(x1,y2) = Nuclearia(x2,y1) = a\% b Nuclearia(x1,y2)=Nuclearia(x2,y1)=a%b
- 修改两条对角线上的值(两条对角线的数组分别为 P o s D i a g PosDiag PosDiag(主对角线)和 N e g D i a g NegDiag NegDiag(次对角线)): P o s D i a g ( x 1 + 1 , y 1 + 1 ) = b , P o s D i a g ( x 2 , y 2 ) = − b , N e g D i a g ( x 1 + 1 , y 2 − 1 ) = − b , N e g D i a g ( x 2 , y 1 ) = b PosDiag(x1+1,y1+1)=b,PosDiag(x2,y2)=-b,NegDiag(x1+1,y2-1)=-b,NegDiag(x2,y1)=b PosDiag(x1+1,y1+1)=b,PosDiag(x2,y2)=−b,NegDiag(x1+1,y2−1)=−b,NegDiag(x2,y1)=b
- 枚举整个国度的 P o s D i a g PosDiag PosDiag和 N e g D i a g NegDiag NegDiag, P o s D i a g ( x , y ) + = P o s D i a g ( x − 1 , y − 1 ) , N e g D i a g ( x , y ) + = N e g D i a g ( x − 1 , y + 1 ) PosDiag(x,y)+=PosDiag(x-1,y-1),NegDiag(x,y)+=NegDiag(x-1,y+1) PosDiag(x,y)+=PosDiag(x−1,y−1),NegDiag(x,y)+=NegDiag(x−1,y+1)
- 枚举整个国度的 N u c l e a r i a Nuclearia Nuclearia, N u c l e a r i a ( x , y ) + = P o s D i a g ( x , y ) + N e g D i a g ( x , y ) Nuclearia(x,y)+=PosDiag(x,y)+NegDiag(x,y) Nuclearia(x,y)+=PosDiag(x,y)+NegDiag(x,y)
- 重复两次:枚举整个国度的
N
u
c
l
e
a
r
i
a
Nuclearia
Nuclearia,
N
u
c
l
e
a
r
i
a
(
x
,
y
)
+
=
N
u
c
l
e
a
r
i
a
(
x
−
1
,
y
)
+
N
u
c
l
e
a
r
i
a
(
x
,
y
−
1
)
−
N
u
c
l
e
a
r
i
a
(
x
−
1
,
y
−
1
)
Nuclearia(x,y)+=Nuclearia(x-1,y)+Nuclearia(x,y-1)-Nuclearia(x-1,y-1)
Nuclearia(x,y)+=Nuclearia(x−1,y)+Nuclearia(x,y−1)−Nuclearia(x−1,y−1)
这就是整个过程了,最后的答案计算方法和上面一样
你以为这就完了吗?
不!没完!
注意题目的最后一句话:如果核电站位于核能国的边境或是在离边境稍近的位置,那么爆炸可能也会影响到核能国之外的方格。影响到核能国外方格的爆炸被称作界限
也就是说 x 1 x1 x1和 y 1 y1 y1有可能 ⩽ 0 \leqslant 0 ⩽0, x 2 x2 x2也有可能 > W >W >W, y 2 y2 y2也有可能 > H >H >H!
对于这个的处理,我们需要再开两个数组 C o l Col Col和 R o w Row Row,存储超出边界的部分,具体的实现就看程序吧,这些细节的处理,这里就不再细讲了
//官方程序
#include <stdio.h>
#include <stdlib.h>
#define MAXWH 10000000
#define MAXN 1000000
#define MAXQ 1000000
typedef long long int huge;
int w, h, n, q;
typedef struct NUCLEARIA
{
huge Info[MAXWH];
huge& operator () (int x, int y) {return Info[(y * w) + x];}
}
NUCLEARIA;
typedef struct PLANT
{
int x;
int y;
int a;
int b;
}
PLANT;
typedef struct QUERY
{
int x1;
int y1;
int x2;
int y2;
}
QUERY;
NUCLEARIA Nuclearia, PosDiag, NegDiag;
PLANT Plant[MAXN];
QUERY Query[MAXQ];
huge Row[MAXWH];
huge Col[MAXWH];
int max(int a, int b)
{
return (a > b) ? a : b;
}
void UpdatePosDiag(int x1, int y1, int x2, int y2, int b)
{
if((x1 < 0) && (y1 < 0))
{
int m = -max(x1, y1);
Nuclearia(0, 0) += m * b;
x1 += m;
y1 += m;
}
if(x1 < 0)
{
int m = -x1;
Col[y1] += b;
Col[y1 + m] -= b;
x1 += m;
y1 += m;
}
if(y1 < 0)
{
int m = -y1;
Row[x1] += b;
Row[x1 + m] -= b;
x1 += m;
y1 += m;
}
PosDiag(x1, y1) += b;
if((x2 + 1 < w) && (y2 + 1 < h)) PosDiag(x2 + 1, y2 + 1) -= b;
}
void UpdateNegDiag(int x1, int y1, int x2, int y2, int b)
{
if(y2 > h - 1)
{
int m = y2 - (h - 1);
x1 += m;
y2 -= m;
}
if(x1 < 0)
{
int m = -x1;
Col[(y2 - m) + 1] -= b;
if(y2 + 1 < h) Col[y2 + 1] += b;
x1 += m;
y2 -= m;
}
if((x1 < w) && (y2 >= 0)) NegDiag(x1, y2) -= b;
if(x2 > w - 1)
{
int m = x2 - (w - 1);
x2 -= m;
y1 += m;
}
if(y1 < 0)
{
int m = -y1;
Row[(x2 - m) + 1] -= b;
if(x2 + 1 < w) Row[x2 + 1] += b;
x2 -= m;
y1 += m;
}
if((x2 + 1 >= 0) && (x2 + 1 < w) && (y1 - 1 >= 0) && (y1 - 1 < h)) NegDiag(x2 + 1, y1 - 1) += b;
}
void SummarizeDiags()
{
for(int x = 0; x < w; x++)
{
for(int y = 0; y < h; y++)
{
if((x) && (y)) PosDiag(x, y) += PosDiag(x - 1, y - 1);
if((x) && (y != h - 1)) NegDiag(x, y) += NegDiag(x - 1, y + 1);
}
}
}
void AddDiags()
{
for(int x = 0; x < w; x++)
{
for(int y = 0; y < h; y++)
{
Nuclearia(x, y) += PosDiag(x, y);
Nuclearia(x, y) += NegDiag(x, y);
}
}
}
void SummarizeLines()
{
for(int x = 1; x < w; x++)
{
Row[x] += Row[x - 1];
}
for(int y = 1; y < h; y++)
{
Col[y] += Col[y - 1];
}
}
void AddLines()
{
for(int x = 0; x < w; x++)
{
Nuclearia(x, 0) += Row[x];
}
for(int y = 0; y < h; y++)
{
Nuclearia(0, y) += Col[y];
}
}
void Summarize()
{
for(int x = 0; x < w; x++)
{
for(int y = 0; y < h; y++)
{
if(x) Nuclearia(x, y) += Nuclearia(x - 1, y);
if(y) Nuclearia(x, y) += Nuclearia(x, y - 1);
if((x) && (y)) Nuclearia(x, y) -= Nuclearia(x - 1, y - 1);
}
}
}
void Print(huge sum, int area)
{
huge rsl = sum / area;
if((sum % area) * 2 >= area)
{
rsl++;
}
printf("%lld\n", rsl);
}
int main()
{
scanf("%d%d", &w, &h);
scanf("%d", &n);
for(int i = 0; i < n; i++)
{
scanf("%d%d%d%d", &(Plant[i].x), &(Plant[i].y), &(Plant[i].a), &(Plant[i].b));
Plant[i].x--;
Plant[i].y--;
}
scanf("%d", &q);
for(int i = 0; i < q; i++)
{
scanf("%d%d%d%d", &(Query[i].x1), &(Query[i].y1), &(Query[i].x2), &(Query[i].y2));
Query[i].x1 -= 2;
Query[i].y1 -= 2;
Query[i].x2--;
Query[i].y2--;
}
for(int i = 0; i < n; i++)
{
PLANT& P = Plant[i];
int d = (P.a - 1) / P.b;
int x1 = P.x - d;
int y1 = P.y - d;
int x2 = P.x + d + 1;
int y2 = P.y + d + 1;
int r = P.a % P.b;
if(r)
{
Nuclearia(max(0, x1), max(0, y1)) += r;
if(x2 < w) Nuclearia(x2, max(0, y1)) -= r;
if(y2 < h) Nuclearia(max(0, x1), y2) -= r;
if((x2 < w) && (y2 < h)) Nuclearia(x2, y2) += r;
x1++;
y1++;
x2--;
y2--;
}
if(P.a >= P.b)
{
UpdatePosDiag(x1, y1, x2, y2, P.b);
UpdateNegDiag(x1, y1, x2, y2, P.b);
}
}
SummarizeDiags();
AddDiags();
SummarizeLines();
AddLines();
Summarize();
Summarize();
for(int i = 0; i < q; i++)
{
QUERY& Q = Query[i];
huge rsl = Nuclearia(Q.x2, Q.y2);
if(Q.x1 >= 0) rsl -= Nuclearia(Q.x1, Q.y2);
if(Q.y1 >= 0) rsl -= Nuclearia(Q.x2, Q.y1);
if((Q.x1 >= 0) && (Q.y1 >= 0)) rsl += Nuclearia(Q.x1, Q.y1);
Print(rsl, (Q.x2 - Q.x1) * (Q.y2 - Q.y1));
}
return 0;
}