本来就是个SB题,结果NT出题人硬是在边界上大搞心态,白写了假算法浪费了一个早上
感觉再多写100行去写边界太NT了,就讲一下这道题核心的思路
假设辐射范围一定在内部,我们可以先求出左上角的点((x_1,y_1))和右下角的点((x_2,y_2))
容易发现此时的贡献形式是一圈一圈往内增加的,手玩一下我们发现在经过主对角线时贡献会增加(b),经过副对角线时贡献会减少(b)
于是我们可以把对角线的贡献先差分了来算,然后在每个矩形的左上角和右上角放上(aoperatorname{mod}b),在右上角和左下角放上(-aoperatorname{mod}b),然后在一起做一边二维前缀和就可以求出每个格子的答案
由于要子矩阵求和,因此我们再做一遍二维前缀和即可
然后刚开始想了一个naive的处理边界的方法,就是把整个矩形扩大到原来的(3 imes 3)倍,然后炸出去的就在外面改就好了
结果死调了一个早上才发现需要扩展的不是矩形而是边长为(max(w,h))的正方形,由于这道题偏偏给的是(w imes h)的限制,于是直接升天
看了下题解好像是要单独处理溢出去的部分,但是非常难写细节很多,感觉除了搞自己一个下午的心态之外没什么积极作用,遂弃了
给份只能过辐射范围在内部的代码跑路了
#include<cstdio>
#include<iostream>
#define RI register int
#define CI const int&
#define int long long
using namespace std;
const int N=200005;
int w,h,n,x[N],y[N],a[N],b[N],q; struct Array
{
int mp[100000000];
inline int* operator [] (CI x)
{
return mp+(x+(w+1)+1)*(3*h+1);
}
}p1,p2;
inline void DEBUG(void)
{
puts("Start Debug:");
for (RI i=1,j;i<=w;++i) for (j=1;j<=h;++j)
printf("%lld%c",p1[i][j],"
"[j==h]);
puts("End Debug");
}
signed main()
{
RI i,j; for (scanf("%lld%lld%lld",&w,&h,&n),i=1;i<=n;++i)
{
scanf("%lld%lld%lld%lld",&x[i],&y[i],&a[i],&b[i]); int d=a[i]/b[i];
int x1=x[i]-d,x2=x[i]+d,y1=y[i]-d,y2=y[i]+d,r;
if (x1<1&&x2>w&&y1<1&&y2>h)
{
r=min(1-x1,min(x2-w,min(1-y1,y2-h)));
x1+=r; x2-=r; y1+=r; y2-=r;
} else r=0; ++x2; ++y2;
p1[x1+1][y1+1]+=b[i]; p1[x2][y2]-=b[i]; p2[x1+1][y2-1]-=b[i]; p2[x2][y1]+=b[i];
}
for (i=-w;i<=2*w;++i) for (j=-h;j<=2*h;++j)
p1[i][j]+=p1[i-1][j-1],p2[i][j]+=p2[i-1][j+1];
for (i=-w;i<=2*w;++i) for (j=-h;j<=2*h;++j) p1[i][j]+=p2[i][j];
for (i=1;i<=n;++i)
{
int d=a[i]/b[i],x1=x[i]-d,x2=x[i]+d,y1=y[i]-d,y2=y[i]+d,r;
if (x1<1&&x2>w&&y1<1&&y2>h)
{
r=min(1-x1,min(x2-w,min(1-y1,y2-h)));
x1+=r; x2-=r; y1+=r; y2-=r;
} else r=0; int v=a[i]-(d-r)*b[i]; ++x2; ++y2;
p1[x1][y1]+=v; p1[x2][y2]+=v; p1[x1][y2]-=v; p1[x2][y1]-=v;
}
for (i=-w;i<=2*w;++i) for (j=-h;j<=2*h;++j)
p1[i][j]+=p1[i-1][j]+p1[i][j-1]-p1[i-1][j-1];
for (i=-w;i<=2*w;++i) for (j=-h;j<=2*h;++j)
p1[i][j]+=p1[i-1][j]+p1[i][j-1]-p1[i-1][j-1];
for (scanf("%lld",&q),i=1;i<=q;++i)
{
int x1,y1,x2,y2; scanf("%lld%lld%lld%lld",&x1,&y1,&x2,&y2);
int ret=p1[x2][y2]-p1[x1-1][y2]-p1[x2][y1-1]+p1[x1-1][y1-1];
if (ret<0) ret+=(1LL<<63); printf("%lld
",(int)(1.0L*ret/((x2-x1+1)*(y2-y1+1))+0.5));
}
return 0;
}
PS:但凡出题人给个(n,mle 1000)之类的都可以过了,现在这样难写地一批
PPS:陈指导的正解