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

Description

Solution

如图,假如我们知道了以任何一个点为顶点的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[2510],yy[2510],aa[2510];
ll sum_slain[1010][1010],sum_line[1010][1010],num[1010][1010];
int add[1010][1010],dev[1010][1010],cur[1010][1010];
void work()
{
    for (int i=1;i<=n;i++) for (int j=1;j<=i;j++)
    {
        add[i][j]+=add[i-1][j];
        dev[i][j]+=dev[i-1][j-1];
        cur[i][j]=cur[i][j-1]+add[i][j]-dev[i][j];
        num[i][j]+=cur[i][j];
        sum_line[i][j]=sum_line[i-1][j]+sum_line[i][j-1]-sum_line[i-1][j-1]+num[i][j];
        sum_slain[i][j]=sum_slain[i-1][j-1]+sum_line[i][j-1]-sum_line[i-1][j-1]+num[i][j];
    }
    memset(add,0,sizeof(add));memset(dev,0,sizeof(dev));cnt=0;
}
ll ans;
int main()
{
    scanf("%d%d",&n,&Q);
    while (Q--)
    {
        scanf("%d%d%d%d",&opt,&x,&y,&a);
        if (opt==1)
        {
            cnt++;
            add[x][y]++;add[x+a][y]--;
            dev[x][y+1]++;dev[x+a][y+a+1]--;
            xx[cnt]=x;yy[cnt]=y;aa[cnt]=a;
            if (cnt==2500) work();
        } else
        {
            ans=sum_slain[x+a-1][y+a-1]-sum_slain[x-1][y-1]-sum_line[x+a-1][y-1]+sum_line[x-1][y-1];
            for (int i=1;i<=cnt;i++)
            {
                int X=min(xx[i]+aa[i]-1,x+a-1);
                int Y=max(yy[i],y);
                int Z=max(xx[i]-yy[i],x-y);
                int len=X-Z-Y+1;
                if (len>0) ans+=1ll*len*(len+1)/2;
            }
            printf("%lld\n",ans);
        }
    }
      
}

 

posted @ 2018-09-27 20:28  _雨后阳光  阅读(178)  评论(0编辑  收藏  举报