LOJ2790&DTOJ2809 [CEOI2015 Day2]核能国度(Nuclearia)

58 篇文章 0 订阅
7 篇文章 0 订阅

题目

题目描述

原题
核能国可以看作一个由 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,ab×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(xPxC,yPyC)
一个方格可能会受到多处核泄漏的影响。
例如,如果一个 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×H2.5×106),分别表示核能国的宽度与高度。
第二行,一个正整数 N N N,表示核电站的个数 ( 1 ≤ N ⩽ 2 × 1 0 5 ) (1 \leq N \leqslant 2×10^5) (1N2×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(1xiW,1yiH,1ai,bi109),表示有一个核电站位于方格 [ 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) (1Q2×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(1x1jx2jW,1y1jy2jH),表示该询问给出的矩形区域的左上角在 [ 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
  1. 2 2 2^2 22方形区域内的总辐射为 14 14 14,所以平均值为 14 ÷ 4 = 3.5 14\div 4=3.5 14÷4=3.5,四舍五入至 4 4 4
  2. 整个核能国的总辐射为 44 44 44,所以平均值为 44 ÷ 12 ≈ 3.67 44\div 12 \approx 3.67 44÷123.67,四舍五入至 4 4 4
  3. 单个格子的平均辐射量就是它所受到的辐射量。
  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,NW108,QW1083
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,NW108,QW1082
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 NWH108,QWH1083
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 NWH108,QWH1082
5 H = 1 , N ⋅ W ≤ 1 0 8 H=1,N\cdot W \leq 10^8 H=1,NW1086
6 H = 1 , N ⋅ W ≤ 1 0 8 H=1,N\cdot W \leq 10^8 H=1,NW1084
7 N ⋅ W ⋅ H ≤ 1 0 8 N\cdot W \cdot H \leq 10^8 NWH1086
8 N ⋅ W ⋅ H ≤ 1 0 8 N\cdot W \cdot H \leq 10^8 NWH1084
9 H = 1 H=1 H=115
10 H = 1 H=1 H=110
11没有符合界限定义的爆炸事件15
12没有符合界限定义的爆炸事件10
1312
148

如果核电站位于核能国的边境或是在离边境稍近的位置,那么爆炸可能也会影响到核能国之外的方格。影响到核能国外方格的爆炸被称作界限

题解

暴力算法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(x1j1,y2j)Nuclearia(x2j,y1j1)+Nuclearia(x1j1,y1j1)

//官方程序
#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数组中,再把左边的和上面的数相加再减去左上的数就可以了
看起来有点抽象,我们可以再总结一下:

  1. 对于每个核电站爆炸事件,计算出它的“势力范围”,左上角为 ( x 1 , y 1 ) (x1,y1) (x1,y1),右下角为 ( x 2 , y 2 ) (x2,y2) (x2,y2)
  2. 标记: 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
  3. 修改两条对角线上的值(两条对角线的数组分别为 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,y21)=b,NegDiag(x2,y1)=b
  4. 枚举整个国度的 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(x1,y1),NegDiag(x,y)+=NegDiag(x1,y+1)
  5. 枚举整个国度的 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)
  6. 重复两次:枚举整个国度的 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(x1,y)+Nuclearia(x,y1)Nuclearia(x1,y1)
    这就是整个过程了,最后的答案计算方法和上面一样
    你以为这就完了吗?
    不!没完!
    注意题目的最后一句话:如果核电站位于核能国的边境或是在离边境稍近的位置,那么爆炸可能也会影响到核能国之外的方格。影响到核能国外方格的爆炸被称作界限
    也就是说 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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值