码迷,mamicode.com
首页 > 其他好文 > 详细

【BZOJ1176】Mokia(CDQ分治)

时间:2018-04-09 23:19:02      阅读:353      评论:0      收藏:0      [点我收藏+]

标签:右上角   整数   span   pre   ace   树套树   结束   问题   else   

【BZOJ1176】Mokia(CDQ分治)

题面

BZOJ权限题啊,,,,
dbzoj真好

Description

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

Input

第一行两个整数,S,W;其中S为矩阵初始值;W为矩阵大小

接下来每行为一下三种输入之一(不包含引号):

"1 x y a"

"2 x1 y1 x2 y2"

"3"

输入1:你需要把(x,y)(第x行第y列)的格子权值增加a

输入2:你需要求出以左下角为(x1,y1),右上角为(x2,y2)的矩阵内所有格子的权值和,并输出

输入3:表示输入结束

Output

对于每个输入2,输出一行,即输入2的答案

Sample Input

0 4
1 2 3 3
2 1 1 3 3
1 2 2 2
2 2 2 3 4
3

Sample Output

3
5

HINT

保证答案不会超过int范围

题解

很明显,只有时间靠前的修改的才会对时间靠后的修改产生影响。
同时,我们有三个维度:时间,\(x\)轴,\(y\)
因此,对于时间进行分治,按照\(x\)排序,
但是这样子每次修改后,很不好解决询问的问题。
我们把询问拆开,拆分为\(4\)个询问
啥?哪四个询问,当然是二维前缀和的询问啊。。。
然后就可以\(CDQ\)分治了。。

说起来,这看一眼就可以用树套树秒掉啊。。。

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<set>
#include<map>
#include<vector>
#include<queue>
using namespace std;
#define ll long long
#define RG register
#define MAX 2222222
#define lb(x) (x&(-x))
inline int read()
{
    RG int x=0,t=1;RG char ch=getchar();
    while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
    if(ch=='-')t=-1,ch=getchar();
    while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
    return x*t;
}
int S,n,tot,tim,cntq;
int c[MAX],ans[MAX];
void add(int x,int w){while(x<=n)c[x]+=w,x+=lb(x);}
int getsum(int x){int ret=0;while(x)ret+=c[x],x-=lb(x);return ret;}
struct Opter{int t,x,y,w,ot,id;}q[MAX],tmp[MAX];
bool operator<(Opter a,Opter b)
{
    if(a.x!=b.x)return a.x<b.x;
    if(a.y!=b.y)return a.y<b.y;
    return a.id<b.id;
}
void CDQ(int l,int r)
{
    if(l==r)return;
    int mid=(l+r)>>1;
    for(int i=l;i<=r;++i)
    {
        if(q[i].t<=mid&&q[i].ot==1)add(q[i].y,q[i].w);
        if(q[i].t>mid&&q[i].ot==2)ans[q[i].id]+=q[i].w*getsum(q[i].y);
    }
    for(int i=l;i<=r;++i)
        if(q[i].t<=mid&&q[i].ot==1)add(q[i].y,-q[i].w);
    int t1=l-1,t2=mid;
    for(int i=l;i<=r;++i)
        if(q[i].t<=mid)tmp[++t1]=q[i];
        else tmp[++t2]=q[i];
    for(int i=l;i<=r;++i)q[i]=tmp[i];
    CDQ(l,mid);CDQ(mid+1,r);
}
int main()
{
    S=read();n=read();
    while(233)
    {
        int opt=read();
        if(opt==3)break;
        if(opt==1)
        {
            int x=read(),y=read();
            q[++tot]=(Opter){++tim,x,y,read(),1};
        }
        else
        {
            int x=read(),y=read(),X=read(),Y=read();
            ans[++cntq]=(y-Y+1)*(X-x+1)*S;//++tim;
            q[++tot]=(Opter){++tim,x-1,y-1,+1,2,cntq};
            q[++tot]=(Opter){++tim,X,Y,+1,2,cntq};
            q[++tot]=(Opter){++tim,x-1,Y,-1,2,cntq};
            q[++tot]=(Opter){++tim,X,y-1,-1,2,cntq};
        }
    }
    sort(&q[1],&q[tot+1]);
    CDQ(1,tot);
    for(int i=1;i<=cntq;++i)printf("%d\n",ans[i]);
    return 0;
}

【BZOJ1176】Mokia(CDQ分治)

标签:右上角   整数   span   pre   ace   树套树   结束   问题   else   

原文地址:https://www.cnblogs.com/cjyyb/p/8763271.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!