Advertisement

【CODECHEF】Chef and Churus(分块)

阅读量:

有一个长度为n的数组A和n个区间[li,ri],有q次操作:

1 x y:把ax改成y

2 x y:求第l个区间到第r个区间的区间和的和。

n,q≤10^5,ai≤10^9

首先,修改一个数肯定会改变区间和以及区间和的和,q≤10^5,应该是要在sqrt(n)或logn完成修改操作,查询操作也是如此。
想到了分块。
数组分块,记录每一个点在该块的前缀和(求块的前缀和时用到),记录每一个块的前缀和(有利于询问在求区间和时用到)。
同时,区间也是同样的分块。对于每一个区间块,用差分的思想,求出dev[i][j],表示在第i个块中,aj出现了多少次(有利于求区间块的和),sum[i],表示区间块的和。

复制代码
    for(int i=1;i<=num;i++)
    {
        for(int j=L[i];j<=R[i];j++)
        {
            dev[i][x[j]]++;
            dev[i][y[j]+1]--;
        }
        for(int j=1;j<=n;j++)
        {
            dev[i][j]+=dev[i][j-1];
            sum[i]+=1ull*dev[i][j]*a[j];
        }
    }

这些量之所以这么设,在于修改时都可以在O(sqrt(n))下修改。

复制代码
    void change(int l,int k)
    {
    int ll=belong[l],ee=a[l];
    a[l]=k;
    for(int i=l;i<=R[ll];i++)
    {
        if(i==L[ll])
        {
            s[i]=a[i];
            continue;
        }
        s[i]=s[i-1]+a[i];
    }
    for(int i=ll;i<=num;i++)
    {
        S[i]+=(a[l]-ee);
    }
    for(int i=1;i<=num;i++)
    {
        sum[i]+=1ll*dev[i][l]*(a[l]-ee);
    }
    }

然后就是分块的基本操作了。已知这些量能够用O(sqrt(n))的时间复杂度计算出来。(需要注意的是答案可能会溢出long long类型,请确保在程序实现时使用unsigned long long类型来存储答案)

复制代码
    unsigned long long get_sum(int l,int r)//add(i,j)表示ai到aj的和
    {
    int ll=belong[l],rr=belong[r];
    unsigned long long ans=0;
    if(ll==rr)
    {
        for(int i=l;i<=r;i++)
        {
            ans+=add(x[i],y[i]);
        }
    }else{
        for(int i=l;i<=R[ll];i++)
        {
            ans+=add(x[i],y[i]);
        }
        for(int i=L[rr];i<=r;i++)
        {
            ans+=add(x[i],y[i]);
        }
        for(int i=ll+1;i<rr;i++)
        {
            ans+=sum[i];
        }
    }
    return ans;
    }

在编写add函数时,请注意以下事项:如果变量i位于一个块的起始位置,则直接相减可能导致越界情况,请特别注意这种情况; 这个问题长时间困扰着我们

复制代码
    long long add(int l,int r)
    {
    int ll=belong[l],rr=belong[r];
    long long ans=0;
    if(ll==rr)
    {
        ans=s[r]-(l==L[ll]?0:s[l-1]);
    }else{
        ans=s[r]+s[R[ll]]-(l==L[ll]?0:s[l-1])+S[rr-1]-S[ll];
    }
    return ans;
    }

为了方便写,可以把每一个块的L,R预处理出来。

全部评论 (0)

还没有任何评论哟~