JZOJ4808. 【NOIP2016提高A组五校联考3】书稿

Description

在这里插入图片描述

  • W*H ≤ 2500000 , N,Q ≤ 200000

Solution

  • 不难发现一滴墨水的影响范围是一个正方形
    在这里插入图片描述
  • 最中间的X是a,之后每往外一层就减b,知道a%b
  • 先将a%b的影响单独取出来。
  • 剩下若干层,从外到里分别是b,2b,3b,…,kb
  • 考虑每一层的矩形分别加b即可成为这个“回”字型的影响图。

b b b b b
b 2b 2b 2b b
b 2b 3b 2b b
b 2b 2b 2b b
b b b b b

  • 将每一层分别加b,根据二维前缀和的方法即可快速加一个矩形
    (+b)-------- (-b)
    |***************|
    (-b)---------(+b)

  • 多层加在一起会变成
    b 0 0 0 0 0 0 -b
    0 b 0 0 0 0 -b 0
    0 0 b 0 0 -b 0 0
    0 0 0 b -b 0 0 0
    0 0 0 -b b 0 0 0
    0 0 -b 0 0 b 0 0
    0 -b 0 0 0 0 b 0
    -b 0 0 0 0 0 0 b

  • 将左上到右下和右上到左下的对角线分别计算。一段对角线的+b或-b依旧用差分区间修改。

  • 这样通过对角线的差分还原出上图,再通过二维前缀和即可还原出每一个位置。然后再用前缀和就可以实现O(1)查询。

  • 现在我们考虑一下出界的情况(即对角线有一部分在边界外时),这也是这题最为坑且难打的地方。
    -在这里插入图片描述

  • 例如红色的对角线上要全部+b

  • 但是出界的那一些显然不能找到地方填。

  • 所以我们考虑这些+b都是对右下的造成影响,所以出界的那一段就等价于橙色的那一段。

  • 所以将出界的部分影射到边界上后区间修改即可(又有一个差分)

  • 其它四个角以及出的不同的界要讨论一波,以此类推。

  • 最后复杂度O(w*h)

  • PS:注意一下精度(鬼知道为什么出题人还要求平均数,难道是专门卡精度的?

#include<cstdio>
#include<cmath>
#include<algorithm>
#include<cstring>
#define maxm 2500005
#define maxn 200005
#define ll long long 
using namespace std;

int w,h,q,n,i,j,k,x,y,a,b,d,xx,yy,t;
ll sum[maxm],level[maxm],pos[maxm],neg[maxm],row[maxm],col[maxm],cnt,ret;

int I(int x,int y){
	if (x<1||y<1||x>w||y>h) return 0; else 
		return (x-1)*h+y;
}

void add(int x,int y,int d){
	if (x<=w&&y<=h) 
		level[I(max(x,1),max(y,1))]+=d;
}

int main(){
	freopen("rezero07.in","r",stdin);
	freopen("ceshi.out","w",stdout);
//	freopen("ceshi.in","r",stdin);
	scanf("%d%d",&w,&h);
	scanf("%d",&n);
	for(i=1;i<=n;i++) {
		scanf("%d%d%d%d",&x,&y,&a,&b);
		d=a/b-1;
		add(x-d-1,y-d-1,a%b),add(x+d+2,y+d+2,a%b);
		add(x-d-1,y+d+2,-a%b),add(x+d+2,y-d-1,-a%b);
		//左上
		xx=x-d,yy=y-d;
		if (xx<1&&yy<1) {
			t=min(1-xx,1-yy);
			level[I(1,1)]+=t*b,xx+=t,yy+=t;
		}
		if (xx<1) {
			t=1-xx;
			row[I(1,yy)]+=b,row[I(1,yy+t)]-=b;
			xx+=t,yy+=t;
		}
		if (yy<1) {
			t=1-yy;
			col[I(xx,1)]+=b,col[I(xx+t,1)]-=b;
			xx+=t,yy+=t;
		}
		pos[I(xx,yy)]+=b;
//		continue;
		//右下
		xx=x+d+2,yy=y+d+2;
		if (xx<=w&&yy<=h) pos[I(xx,yy)]-=b;
//		continue;
		//左下
		xx=x+d+1,yy=y-d;
		if (xx>w&&y<1) {
			t=min(xx-w,1-yy);
			xx-=t,yy+=t;
		}
		if (xx>w) {
			t=xx-w;
			xx-=t,yy+=t;
		}
		if (yy<1) {
			t=1-yy;
			col[I(xx-t+1,1)]-=b;
			if (xx+1<=w) col[I(xx+1,1)]+=b;
			xx-=t,yy+=t;
		}
		neg[I(xx,yy)]-=b;
		//右上
		xx=x-d-1,yy=y+d+2;
		if (xx>=1&&yy<=h) neg[I(xx,yy)]+=b;
		else xx++,yy--;
		if (xx<1&&yy>h) {
			t=min(1-xx,yy-h);
			xx+=t,yy-=t;
		} 
		if (xx<1) {
			t=1-xx;
			row[I(1,yy-t+1)]-=b;
			if (yy+1<=h) row[I(1,yy+1)]+=b;
			xx+=t,yy-=t;
		}
		if (yy>h) {
			t=yy-h;
			xx+=t,yy-=t;
		}
	}

	for(i=1;i<=w;i++) for(cnt=0,j=1;j<=h;j++) 
		cnt+=row[I(i,j)],level[I(i,j)]+=cnt;
	for(j=1;j<=h;j++) for(cnt=0,i=1;i<=w;i++) 
		cnt+=col[I(i,j)],level[I(i,j)]+=cnt;
	for(x=1,y=1;y<=h;y++) for(cnt=0,i=x,j=y;i<=w&&j<=h;i++,j++)
		cnt+=pos[I(i,j)],level[I(i,j)]+=cnt;
	for(x=2,y=1;x<=w;x++) for(cnt=0,i=x,j=y;i<=w&&j<=h;i++,j++)
		cnt+=pos[I(i,j)],level[I(i,j)]+=cnt;
	for(x=1,y=1;x<=w;x++) for(cnt=0,i=x,j=y;i>=1&&j<=h;i--,j++) 
		cnt+=neg[I(i,j)],level[I(i,j)]+=cnt;
	for(x=w,y=2;y<=h;y++) for(cnt=0,i=x,j=y;i>=1&&j<=h;i--,j++)
		cnt+=neg[I(i,j)],level[I(i,j)]+=cnt;
	
	for(i=1;i<=w;i++) for(j=1;j<=h;j++) 
		level[I(i,j)]+=level[I(i-1,j)]+level[I(i,j-1)]-level[I(i-1,j-1)];
	for(i=1;i<=w;i++) for(j=1;j<=h;j++) 
		sum[I(i,j)]=level[I(i,j)]+sum[I(i-1,j)]+sum[I(i,j-1)]-sum[I(i-1,j-1)];
	
	
	scanf("%d",&q);
	while (q--) {
		scanf("%d%d%d%d",&x,&y,&i,&j);
		ll ans=sum[I(i,j)]-sum[I(x-1,j)]-sum[I(i,y-1)]+sum[I(x-1,y-1)];
		ll s=(i-x+1)*(j-y+1);
		ll ret=ans/s;
		if ((ans%s)*2>=s) ret++;
		printf("%lld
",ret);
	}
}
原文地址:https://www.cnblogs.com/DeepThinking/p/11700940.html