题解:乱搞
这个题测试的时候写的线段树区间修改区间查询,然后get到50分。。。。
这个题的正解其实就是个乱搞。
每一个修改对每一个询问的影响可以O(1)的计算,需要判断两个三角形的位置关系,然后计算重叠部分的点数。
然后我们可以对每个修改进行差分,当累积的未处理的操作数达到一定值的时候,我们就将每个位置的数查询出来,然后记录到前缀和数组中,每次这么做的时间复杂度是O(n^2)
然后每次查询的时候只需要查询前缀和数组,然后再o(1)计算未加入前缀和的修改对当前询问的影响即可。
时间复杂度O(q/k*(n^2)+q*k) 当k=1000的时候就可以通过了。
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
#define N 1003
#define LL long long
using namespace std;
LL sum[N][N],ch[N][N];
int n,m,posx[N*100],posy[N*100],a1[N*100];
void change(int x,int y,int a)
{
for (int i=x;i<=x+a-1;i++){
int y1=y+i-x;
ch[i][y]++; ch[i][y1+1]--;
}
}
void build()
{
memset(sum,0,sizeof(sum));
for (int i=1;i<=n;i++)
{
LL t=0;
for (int j=1;j<=i;j++) t+=ch[i][j],sum[i][j]=sum[i][j-1]+t;
}
}
int main()
{
freopen("delta.in","r",stdin);
freopen("delta.out","w",stdout);
scanf("%d%d",&n,&m);
int k=0; int x1,y1,x2,y2;
for (int i=1;i<=m;i++){
int opt,x,y,a; scanf("%d%d%d%d",&opt,&x,&y,&a);
if (opt==1) {
k++; posx[k]=x; posy[k]=y; a1[k]=a; change(x,y,a);
if (k==1000) build(),k=0;
}
else {
LL ans=0;
for (int j=x;j<=x+a-1;j++) ans+=sum[j][y+j-x]-sum[j][y-1];
for (int j=1;j<=k;j++){
if (posy[j]==y&&x<posx[j]||y<posy[j]) {
x1=x; y1=y;
x2=posx[j]; y2=posy[j];
}
else {
x1=posx[j]; y1=posy[j];
x2=x; y2=y;
}
x2=max(x2,x1+y2-y1);
int len=max(min(x+a,posx[j]+a1[j])-x2,0);
ans+=(LL)(len+1)*(LL)len/2;
}
printf("%I64d\n",ans);
}
}
}