CDQ分治 - 单点修改区间查询

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/monochrome00/article/details/85246117

题目链接<https://www.luogu.org/problemnew/show/P3374>


题解:

一共有两维,一维是操作的时间,一维是操作的位置。一开始时间是排好序的,只需要对位置这一维分治统计。

利用前缀和的思想,把答案记为sum[r]-sum[l-1],所以把查询操作拆成两个:r和l-1。


#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N=5e6+7;
int n,m,tot,num=0;
struct Node{
    int tp,id;
    ll val;
    bool operator<(const Node a)const{
        if(id==a.id) return tp<a.tp;
        return id<a.id;
    }
}a[N],b[N];
ll ans[N];
void cdq(int l,int r){
    if(l==r) return;
    int m=l+r>>1;
    cdq(l,m);cdq(m+1,r);
    int p=l,q=m+1,i=l;
    ll sum=0;
    while(p<=m&&q<=r){
        if(a[p]<a[q]){
            if(a[p].tp==1) sum+=a[p].val;
            b[i++]=a[p++];
        }
        else{
            if(a[q].tp==2) ans[a[q].val]-=sum;
            else if(a[q].tp==3)ans[a[q].val]+=sum;
            b[i++]=a[q++];
        }
    }
    while(p<=m) b[i++]=a[p++];
    while(q<=r){
        if(a[q].tp==2) ans[a[q].val]-=sum;
        else if(a[q].tp==3)ans[a[q].val]+=sum;
        b[i++]=a[q++];
    }
    for(int i=l;i<=r;i++) a[i]=b[i];
}
int main()
{
    scanf("%d%d",&n,&m);
    for(ll i=1;i<=n;i++){
        a[++tot].tp=1;a[tot].id=i;
        scanf("%lld",&a[tot].val);
    }
    while(m--){
        int tp;
        scanf("%d",&tp);
        if(tp==1){
            a[++tot].tp=1;
            scanf("%d%lld",&a[tot].id,&a[tot].val);
        }
        else{
            int l,r;
            scanf("%d%d",&l,&r);
            num++;
            a[++tot].tp=2;
            a[tot].id=l-1;a[tot].val=num;
            a[++tot].tp=3;
            a[tot].id=r;a[tot].val=num;
        }
    }
    cdq(1,tot);
    for(ll i=1;i<=num;i++) printf("%lld\n",ans[i]);
}

猜你喜欢

转载自blog.csdn.net/monochrome00/article/details/85246117