[2016北京集训试题15]cot-[分块]

时间:2023-03-09 06:49:24
[2016北京集训试题15]cot-[分块]

Description

[2016北京集训试题15]cot-[分块]

Solution

[2016北京集训试题15]cot-[分块]

如图,假如我们知道了以任何一个点为顶点的135-180度的前缀和和90-180度的前缀和,我们就可以搞出三角形的面积。

差分。add[i][j]和dev[i][j]都表示相对点[i][j-1],点[i][j]应该+或-的大小。这样只要我们需要,可以在O(n2)的时间里求出整个图的前缀和。

然后,不可能每一次查询都求一次前缀和的。考虑分块。记录当前添加的修改的操作数cnt。如果cnt=2500,则把图的前缀和全部求出来,对cnt,add,dev初始化。

假如中途有询问,就计算好之前分出的若干块对本次询问的贡献后,i直接从1到cnt枚举,判断当前的修改对询问的贡献。

Code

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
using namespace std;
typedef long long ll;
int n,Q;int opt,x,y,a,cnt,xx[],yy[],aa[];
ll sum_slain[][],sum_line[][],num[][];
int add[][],dev[][],cur[][];
void work()
{
for (int i=;i<=n;i++) for (int j=;j<=i;j++)
{
add[i][j]+=add[i-][j];
dev[i][j]+=dev[i-][j-];
cur[i][j]=cur[i][j-]+add[i][j]-dev[i][j];
num[i][j]+=cur[i][j];
sum_line[i][j]=sum_line[i-][j]+sum_line[i][j-]-sum_line[i-][j-]+num[i][j];
sum_slain[i][j]=sum_slain[i-][j-]+sum_line[i][j-]-sum_line[i-][j-]+num[i][j];
}
memset(add,,sizeof(add));memset(dev,,sizeof(dev));cnt=;
}
ll ans;
int main()
{
scanf("%d%d",&n,&Q);
while (Q--)
{
scanf("%d%d%d%d",&opt,&x,&y,&a);
if (opt==)
{
cnt++;
add[x][y]++;add[x+a][y]--;
dev[x][y+]++;dev[x+a][y+a+]--;
xx[cnt]=x;yy[cnt]=y;aa[cnt]=a;
if (cnt==) work();
} else
{
ans=sum_slain[x+a-][y+a-]-sum_slain[x-][y-]-sum_line[x+a-][y-]+sum_line[x-][y-];
for (int i=;i<=cnt;i++)
{
int X=min(xx[i]+aa[i]-,x+a-);
int Y=max(yy[i],y);
int Z=max(xx[i]-yy[i],x-y);
int len=X-Z-Y+;
if (len>) ans+=1ll*len*(len+)/;
}
printf("%lld\n",ans);
}
} }