Mokia 摩基亚

题目链接:[https://www.luogu.com.cn/problem/P4390]

快捷版题意:

维护一个\(W*W\)的矩阵,初始值均为\(S\).每次操作可以增加某格子的权值,或询问某子矩阵的总权值.修改操作数\(M<=160000\),询问数\(Q<=10000,W<=2000000.\)

思路:

第一反应二维树状数组,然而看到\(W<=2000000\)便望而却步。
想到今天在练\(cdq\)分治,于是往这个方向靠。
首先,容易想到子矩阵总权值可拆分为四个前缀子矩阵权值和。
那么,前缀子矩阵权值和权值和怎么求呢?
初始值\(S\)直接加就可以了。
考虑到一个修改操作对求和有贡献,当且仅当它在需要求的前缀子矩阵内部。
设前缀子矩阵右下角坐标为\((x,y)\),则对于对其有贡献的点P,满足\(xp<=x\)\(yp<=y\)
发现这原来就是一个裸的三维偏序,上cdq分治即可。

注意事项:

  • 树状数组查询时可能会有0,要特判一下。
  • 数组要开大些,因为一个询问会被分裂长四个。
  • 还有变量名不要手残打错。

    code:

#include<bits/stdc++.h>
using namespace std;
const int N=2e5+50;
const int W=2e6+50;
int s,w,n;
struct node{int x,y,v,tp,id,ans;}a[N],b[N];
bool operator<(node x,node y){return x.x<y.x;}
inline int read()
{
    int s=0,w=1; char ch=getchar();
    for(;!isdigit(ch);ch=getchar())if(ch=='-')w=-1;
    for(;isdigit(ch);ch=getchar())s=(s<<1)+(s<<3)+(ch^48);
    return s*w;
}
struct tree{
    int c[W];
    inline int lowbit(int x){return x&(-x);}
    inline void add(int x,int v)
    {
        if(!x) return;
        for(;x<=w;x+=lowbit(x))c[x]+=v;
    }
    inline int query(int x)
    {
        if(!x) return 0;
        int ans=0;
        for(;x;x-=lowbit(x))ans+=c[x];
        return ans;
    }
}T;
void cdq(int l,int r)
{
    if(l==r) return;
    int mid=l+r>>1;
    cdq(l,mid);cdq(mid+1,r);
    sort(b+l,b+mid+1);sort(b+mid+1,b+r+1);
    int i=l,j=mid+1;
    for(;j<=r;++j)
    {
        for(;i<=mid&&b[i].x<=b[j].x;++i)
            if(b[i].tp==1) T.add(b[i].y,b[i].v);
        if(b[j].tp==2)
            a[b[j].id].ans+=T.query(b[j].y);
    }
    for(int e=l;e<i;++e)
        if(b[e].tp==1) T.add(b[e].y,-b[e].v);
}
int main()
{
    s=read(),w=read();
    while(7)
    {
        int opt=read();
        if(opt==3) break;
        if(opt==1)
            a[++n].x=read(),a[n].y=read(),a[n].v=read(),a[n].tp=1,a[n].id=n;
        else
        {
            int x11=read(),y11=read(),x22=read(),y22=read();
            a[++n].x=x22,a[n].y=y22,a[n].tp=2,a[n].id=n;
            a[++n].x=x11-1,a[n].y=y22,a[n].tp=2,a[n].id=n;
            a[++n].x=x22,a[n].y=y11-1,a[n].tp=2,a[n].id=n;
            a[++n].x=x11-1,a[n].y=y11-1,a[n].tp=2,a[n].id=n;
        }
    }
    for(int i=1;i<=n;++i) b[i]=a[i];
    cdq(1,n);
    for(int i=1;i<=n;++i)
        if(a[i].tp==2)
        {
            int bas=abs(a[i+1].x-a[i+2].x)*abs(a[i+1].y-a[i+2].y)*s;
            printf("%d\n",bas+a[i].ans-a[i+1].ans-a[i+2].ans+a[i+3].ans);
            ++i,++i,++i;
        }
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/zmyzmy/p/11962695.html