cdq分治入门

看了几天cdq分治,刚看的时候感觉这样做是对的,但是又不知道为啥是对的,只是凭感觉在写。

后来再慢慢看就明白了。

cdq分治是为了降低维度,使原来的问题变得简单。通常可以顶替复杂的数据结构。

使用cdq分治的条件:

1.原问题可以转化为多维偏序问题。

2.修改相互独立。

3.题目允许离线。

其实归并排序求逆序对的过程就是一个简单的cdq分治。

一个简单的cdq分治的运用场景:

1。将某个位置上的值加上x

2。查询区间的和。

我们可以转化为二维偏序问题,第一维为时间,第二维为x坐标。

对于一个查询,我们要求的就是小于当前时间的&&x坐标小于当前查询坐标的值。

每次只统计左区间修改对右区间查询的影响。

#include<iostream>
#include<cstdio>
#include<vector>
#include<cstring>
#define rep(i,j,k) for(int i=j;i<=k;i++)
#define per(i,j,k) for(int i=j;i>=k;i--)
#define inf 0x3f3f3f3f
#define LL long long
#define fir first
#define sec second
#define lson rt<<1
#define rson rt<<1|1
#define sq(x) (x)*(x)
#define sca(x) scanf("%d",&x)
#define pb(x) push_back(x)
using namespace std;
#define N 5000005
#define maxn 2000005

struct node
{
    int type,val,id;
    int qid;
    friend bool operator <(node x,node y)
    {
        if(x.id!=y.id)return x.id<y.id;
        else return x.type<y.type;
    }
}q[N],q1[N];

LL ou[N];
int tot;
void add(int type,int id,int val,int qid)
{
    q[tot].type=type;
    q[tot].id=id;
    q[tot].val=val;
    q[tot].qid=qid;
    tot++;
}

void cdq(int l,int r)
{
    if(l==r)return ;
    int m=(l+r)>>1;
    cdq(l,m);
    cdq(m+1,r);
    LL sum=0;
    int L=l;
    int R=m+1;
    int now=l;
    while(L<=m&&R<=r)
    {
        if(q[L]<q[R])
        {
            if(q[L].type==1)sum+=q[L].val;
            q1[now++]=q[L++];
        }
        else
        {
            if(q[R].type==2)ou[q[R].qid]-=sum;
            if(q[R].type==3)ou[q[R].qid]+=sum;
            q1[now++]=q[R++];
        }
    }
    while(L<=m)
    {
        if(q[L].type==1)sum+=q[L].val;
        q1[now++]=q[L++];
    }
    while(R<=r)
    {
        if(q[R].type==2)ou[q[R].qid]-=sum;
        if(q[R].type==3)ou[q[R].qid]+=sum;
        q1[now++]=q[R++];
    }
    rep(i,l,r)q[i]=q1[i];
}

int main()
{
    int n,m;
    scanf("%d%d",&n,&m);
    int tmp;
    tot=1;
    rep(i,1,n)sca(tmp),add(1,i,tmp,0);
    int qid=1;
    rep(i,1,m)
    {
        int x,y,z;
        scanf("%d%d%d",&x,&y,&z);
        if(x==1) add(1,y,z,0);
        else add(2,y-1,0,qid),add(3,z,0,qid),qid++;
    }
    cdq(1,tot-1);
    rep(i,1,qid-1)printf("%lld\n",ou[i]);
}

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值