[BZOJ2683]简单题(cdq分治)

题目:

我是超链接

题解:

Emmm,这不是那道【简单题】吗,一眼二维树状数组
这道题目不强制在线啦,那我们可以用cdq分治
把每个询问拆成二维前缀和的形式,用乘1/-1的方式确定正负,至于方格里每个数的值嘛,我们就在权值树状数组中加多少就好啦
要对每个询问求符合如下条件的修改操作的贡献:
1.时间在它之前
2.x坐标小于等于它
3.y坐标小于等于它
三维偏序!
按照时间分治,x坐标排序,y坐标树状数组
“拆询问”和“按照时间排序”的思路都是CDQ分治的题目中非常常用的,有利于找到题目中的三维偏序关系

然后调了好久发现是把f赋给了jl。。。

代码:

#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;
const int N=500005;
struct hh{int x,y,id,z,f;}jl[800005],f[800005];
int n,c[N],ans[N],lj;bool flag[N];
void add(int loc,int val)
{
    for (int i=loc;i<=n;i+=i&(-i)) 
      c[i]+=val;
}
int qurry(int loc)
{
    int ans=0;
    for (int i=loc;i>=1;i-=i&(-i))  ans+=c[i];
    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 t1=l,t2=mid+1;
    for (int i=l;i<=r;i++)
    {
        if ((t1<=mid && f[t1].x<=f[t2].x) || t2>r) 
        {
            jl[i]=f[t1];
            if (!flag[f[t1].id]) add(f[t1].y,f[t1].z);
            t1++;
        }
        else 
        {
            jl[i]=f[t2];
            ans[f[t2].id]+=f[t2].f*qurry(f[t2].y);
            t2++;
        }
    }
    for (int i=l;i<=mid;i++) 
      if (!flag[f[i].id]) add(f[i].y,-f[i].z);
    for (int i=l;i<=r;i++) f[i]=jl[i];
}
int main()
{
    scanf("%d",&n);int T=0,id,gs=0;
    while (scanf("%d",&id))
    {
        if (id==3) break;
        ++T;
        if (id==1) f[++gs].id=T,scanf("%d%d%d",&f[gs].x,&f[gs].y,&f[gs].z),f[gs].f=0;
        else if (id==2)
        {
            flag[T]=1;int x,y,a,b;
            scanf("%d%d%d%d",&a,&b,&x,&y);
            f[++gs].x=a-1; f[gs].y=b-1; f[gs].f=1; f[gs].id=T;
            f[++gs].x=a-1; f[gs].y=y; f[gs].f=-1; f[gs].id=T;
            f[++gs].x=x; f[gs].y=b-1; f[gs].f=-1; f[gs].id=T;
            f[++gs].x=x; f[gs].y=y; f[gs].f=1; f[gs].id=T;
        }
    }
    cdq(1,gs);
    for (int i=1;i<=T;i++) if (flag[i]) printf("%d\n",ans[i]);
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值