[COGS 577] 蝗灾

本文介绍使用CDQ分治策略解决方阵单点修改及小矩阵和查询的问题。通过将查询拆分为四部分,并利用树状数组维护区间修改与查询,最终实现高效求解。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

描述

一个方阵,支持单点修改,查询一个小矩阵的和。

思路

蒟蒻并不会树套树,但最近学了点CDQ分治的皮毛,做了一下这道题。
对于修改直接记录。
对于查询拆成四部分。

类似于矩阵前缀和,运用查分的思想。
ans=1+2-3-4;
然后cdq中维护x升序。以y为下标维护树状数组。
记录左区间修改,修改右区间的查询。

代码

#include <iostream>
#include <cstdio>
using namespace std;
const int maxn=1000000+10;
struct node
{
    int val,type,tag,x,y;
    bool operator < (const node &o) const
    {
        if(x!=o.x) return x<o.x;
        else if(y!=o.y) return y<o.y;
        else return type<o.type;
    }
}a[maxn],b[maxn],tt[maxn];
int n,m,tot,totx,ans[maxn];
int tree[maxn];
int lowbit(int x)
{
    return x&(-x);
}
void modify(int x,int d)
{
    while(x<=n)
    {
        tree[x]+=d;
        x+=lowbit(x);
    }
}
int query(int x)
{
    int ans=0;
    while(x)
    {
        ans+=tree[x];
        x-=lowbit(x);
    }
    return ans;
}
void cdq(int l,int r)
{
    if(l==r) return;
    int mid=(l+r)>>1;
    cdq(l,mid); cdq(mid+1,r);
    int p1=l,p2=mid+1,cnt=0;
    for(int i=l; i<=r; i++)
    {
        if((p1<=mid && a[p1]<a[p2]) || p2>r)
        {
            if(a[p1].type==1)
            {
                cnt++; tt[cnt]=a[p1]; modify(a[p1].y,a[p1].val);
            }
            b[i]=a[p1]; p1++;
        }
        else
        {
            if(a[p2].type==2)
            {
                ans[a[p2].val]+=a[p2].tag*query(a[p2].y);
            }
            b[i]=a[p2]; p2++;
        }
    }
    for(int i=l; i<=r; i++) a[i]=b[i];
    for(int i=1; i<=cnt; i++)
    {
        modify(tt[i].y,-tt[i].val);
    }
}
int main()
{
    freopen("locust.in","r",stdin);
    freopen("locust.out","w",stdout);
    scanf("%d %d",&n,&m);
    while(m--)
    {
        int opt;
        scanf("%d",&opt);
        if(opt==1)
        {
            int x,y,w; scanf("%d %d %d",&x,&y,&w);
            tot++; a[tot].type=1; a[tot].x=x; a[tot].y=y;
            a[tot].val=w;
        }
        else
        {
            int xx,yy,x2,y2; totx++;
            scanf("%d %d %d %d",&xx,&yy,&x2,&y2);
            //拆成四部分,建议画一下图
            tot++; a[tot]=(node){totx,2,1,x2,y2};
            tot++; a[tot]=(node){totx,2,1,xx-1,yy-1};
            tot++; a[tot]=(node){totx,2,-1,xx-1,y2};
            tot++; a[tot]=(node){totx,2,-1,x2,yy-1};
        }
    }
    cdq(1,tot);
    for(int i=1; i<=totx; i++)
    {
        printf("%d\n",ans[i]);
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值