CDQ分治&整体二分练习1——P4390 [BOI2007]Mokia 摩基亚

蒟蒻的垂死挣扎

很裸的一道CDQ分治题,这题对于每个询问处理为二维前缀的形式,那么就可以分裂成四个查询,然后以时间、x、y三维做CDQ分治,大概怎么搞都可以吧。

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<queue>
#include<map>
#include<set>
#define ll long long
#define MOD 1000000007
#define N 210000
#define M 10010000
#define RG register

using namespace std;

inline ll read(){
    RG ll x=0,o=1; RG char ch=getchar();
    while((ch<'0'||ch>'9')&&ch!='-') ch=getchar();
    if(ch=='-') o=-1,ch=getchar();
    while(ch>='0'&&ch<='9') x=((x<<3)+(x<<1))+ch-'0',ch=getchar();
    return x*o;
}

struct mona { int t,op,x,y; ll val,id,opt; } s[N],q[N];
inline bool cmp(mona x,mona y) { return x.t<y.t; }
int n,tr[2001000],top; ll ans[11000];

inline void Update(int x,ll y){
    for(RG int i=x;i<=n&&i;i+=(i&-i)) tr[i]+=y;
}
inline ll Query(int x){ RG ll ans=0;
    for(RG int i=x;i;i-=(i&-i)) ans+=tr[i]; return ans;
}

inline void CDQ(int l,int r){
    if(l==r) return ;  int mid=(l+r)>>1;
    CDQ(l,mid),CDQ(mid+1,r); RG int i,j,now;
    for(i=l,j=mid+1,now=l-1;i<=mid,j<=r;)
        if(s[i].x<s[j].x&&i<=mid) q[++now]=s[i++];
        else if(s[i].x>s[j].x&&j<=r) q[++now]=s[j++];
        else if(s[i].op==1&&i<=mid) q[++now]=s[i++];
        else q[++now]=s[j++];
    while(i<=mid) q[++now]=s[i++];
    while(j<=r)   q[++now]=s[j++];
    for(i=l;i<=r;++i){
        s[i]=q[i];
        if(s[i].op==1&&s[i].t<=mid) Update(s[i].y,s[i].val);
        if(s[i].op==2&&s[i].t>mid)  s[i].val+=Query(s[i].y);
    }
    for(i=l;i<=r;++i) if(s[i].op==1&&s[i].t<=mid) Update(s[i].y,-s[i].val);
}

int main(){
    read(),n=read(); RG int op,t=0;
    while((op=read())!=3)
        if(op==1) s[++t]=(mona) { t,op,read(),read(),read() };
        else{
            int x=read(),y=read(),tx=read(),ty=read(); ++top;
            s[++t]=(mona) { t,op,x-1,y-1,0,top,+1 },s[++t]=(mona) { t,op,tx,ty,0,top,+1 };
            s[++t]=(mona) { t,op,x-1,ty,0,top,-1 },s[++t]=(mona) { t,op,tx,y-1,0,top,-1 };
        }
    CDQ(1,t);
    for(RG int i=1;i<=t;++i) if(s[i].op==2) ans[s[i].id]+=s[i].opt*s[i].val;
    for(RG int i=1;i<=top;++i) printf("%lld\n",ans[i]);
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值