cdq分治解决树状数组例题

树状数组的一个例题:一组数据的单点修改区间查询操作。 

这里是看到了__stdcall的这篇博客才明白。(只是了解了目前的这种解法还不敢说完全明白蒟蒻瑟瑟发抖)。

首先第一步便是把所有的操作都给他变成查询或者修改操作,然后查询操作因为是区间查询就给他改成两个查询然后进行标记来把这个操作从区间和变成前缀和相差。

  1. 合并问题的时候统计“加上的值的前缀和”,只能统计左边区间内的修改操作,改动查询结果的时候,只能修改右边区间内的查询结果。因为只有左边区间内的修改值对右边区间内的查询结果的影响还没有统计。(一开始就这里不太明白,看到这句话之后就了解了)

这个查询和修改的时间顺序已经是排好的就是按照输入顺序, 而且在归并的时候不管是重的或者当前区间没有统计到的都会被计算到这个区间里面去(学的还是太肤浅了呀)。

#include <bits/stdc++.h>
using namespace std;
struct Node
{
    long long val;
    int id,typ;
    bool operator<(const Node &x)const{
        return id!=x.id?id<x.id:typ<x.typ;
    }
};
Node a[2000000],b[2000000];
long long int tot,totx,ans[2000000];
void CDQ(int l,int r)
{
    if(l==r)
        return ;
    int M=(l+r)>>1;
    CDQ(l,M),CDQ(M+1,r);
    int k1=l,k2=M+1;
    long long int sum=0;
    for(int i=l;i<=r;i++)
    {
        if(k1<=M&&a[k1]<a[k2]||k2>r)
        {
            if(a[k1].typ==1)
                sum+=a[k1].val;
            b[i]=a[k1++];
        }
        else
        {
            if(a[k2].typ==2)ans[a[k2].val]-=sum;
            else if(a[k2].typ==3)ans[a[k2].val]+=sum;
            b[i]=a[k2++];
        }
        //cout<<sum<<endl;
    }
    /*for(int i=l;i<=r;i++)
        {
           // a[i]=b[i];
            cout<<a[i].id<<' '<<a[i].val<<' '<<a[i].typ<<' '<<'|'<<' ';
        }
        cout<<endl;*/
    for(int i=l;i<=r;i++)
        {
            a[i]=b[i];
            //cout<<a[i].id<<' '<<a[i].val<<' '<<a[i].typ<<' '<<'|'<<' ';
        }
        //cout<<endl;
}
int main()
{
    tot=0,totx=0;
    int n,m;
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)
    {
        tot++;
        a[tot].id=i,a[tot].typ=1;
        scanf("%d",&a[tot].val);
    }
    for(int i=1;i<=m;i++)
    {
        tot++;
        int t;
        scanf("%d",&t);
        a[tot].typ=t;
        if(t==1)
        {
            scanf("%d%lld",&a[tot].id,&a[tot].val);
        }
        else
        {
            totx++;
            int l,r;
            scanf("%d%d",&l,&r);
            a[tot].id=l-1,a[tot].val=totx;
            tot++;
            a[tot].typ=3,a[tot].id=r,a[tot].val=totx;
        }
    }
    /*for(int i=1;i<=tot;i++)
    {
        cout<<a[i].id<<' '<<a[i].val<<' '<<a[i].typ<<' '<<'|'<<' ';
    }
    cout<<endl;*/
    CDQ(1,tot);
    for(int i=1;i<=totx;i++)
        cout<<ans[i]<<endl;
    return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值