【CDQ】 BZOJ 1176 MOKIA

题意:维护一个W*W的矩阵,每次操作可以增加某格子的权值,或询问某子矩阵的总权值

思路:CDQ模板题吧,点和矩形(4个点)都看成点,然后利用矩阵的前缀和可求出

代码:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>

using namespace std;

const int maxn=200200;

int s,w;
int n;

struct Node
{
    int x,y,kind,pos,num;

    bool operator<(const Node& node) const
    {
        return x<node.x;
    }

    void toString()
    {
        printf(" (%d,%d) k: %d p: %d num: %d\n",x,y,kind,pos,num);
    }

}T[maxn],nT[maxn];

bool cmp(Node a,Node b)
{
    return a.pos<b.pos;
}

/***********树状数组**************/

int C;
int Color[maxn*10],tree[maxn*10];

inline int lowbit(int x)
{
    return x&(-x);
}

void Add(int p,int v)
{
    for(int i=p;i<=w;i+=lowbit(i))
    {
        if(Color[i]!=C) tree[i]=0;
        Color[i]=C;
        tree[i]+=v;
    }
}

int Sum(int p)
{
    int ret=0;
    for(int i=p;i;i-=lowbit(i))
    {
        if(Color[i]==C)
            ret+=tree[i];
    }
    return ret;
}

/****************CDQ*********************/

void CDQ(int l,int r)
{
    if(l==r) return;

    int mid=(l+r)/2;

    int l1=l,l2=mid+1;

    for(int i=l;i<=r;i++)
    {
        if(T[i].pos<=mid) nT[l1++]=T[i];
        else nT[l2++]=T[i];
    }

    memcpy(T+l,nT+l,sizeof(T[0])*(r-l+1));

    CDQ(l,mid);

    /// 左半部分对右半部分的影响

    int j=l; C++;
    for(int i=mid+1;i<=r;i++)
    {
        for(;T[j].x<=T[i].x&&j<=mid;j++)
        {
            if(T[j].kind==1)
            {
                Add(T[j].y,T[j].num);
            }
        }
        if(T[i].kind==2)
        {
            T[i].num+=Sum(T[i].y);
        }
    }

    CDQ(mid+1,r);

    /// Recover

    l1=l,l2=mid+1;
    for(int i=l;i<=r;i++)
    {
        if((T[l1]<T[l2]&&l1<=mid)||l2>r) nT[i]=T[l1++];
        else nT[i]=T[l2++];
    }

    memcpy(T+l,nT+l,sizeof(T[0])*(r-l+1));
}

int main()
{
    scanf("%d%d",&s,&w);
    int k,x1,y1,x2,y2,S;
    while(scanf("%d",&k)&&k!=3)
    {
        if(k==1)
        {
            scanf("%d%d%d",&x1,&y1,&S);
            n++; T[n]=(Node){x1,y1,1,n,S};
        }
        else if(k==2)
        {
            scanf("%d%d%d%d",&x1,&y1,&x2,&y2);

            /// Add 4 Node
            n++; T[n]=(Node){x1-1,y1-1,2,n,0};
            n++; T[n]=(Node){x1-1,y2,  2,n,0};
            n++; T[n]=(Node){x2,y1-1,  2,n,0};
            n++; T[n]=(Node){x2,y2,    2,n,0};
        }
    }

    sort(T+1,T+1+n);
    CDQ(1,n);
    sort(T+1,T+1+n,cmp);
    for(int i=1;i<=n;i++)
    {
        if(T[i].kind==2)
        {
            int ans=0;

            ans+=T[i].num; i++;
            ans-=T[i].num; i++;
            ans-=T[i].num; i++;
            ans+=T[i].num;

            printf("%d\n",ans);
        }
    }
    return 0;
}
View Code

 

转载于:https://www.cnblogs.com/Rojo/p/4867173.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值