POJ 3468 树状数组区间修改+区间查询

题目传送门

对于区间修改+单点查询,我们是用差分的思想去完成,一直维护一个差分数组,到时候查询的时候差分的前缀和就行了。

那么对于区间查询,我们不可能对区间中每一个点都去查询,然后相加,这样时间复杂度过不去,于是,我们就要想更加好的方法。

我们要对一个区间求和,即a1+a2+a3+…+an,即对差分数组d1+d1+d2+d1+d2+d3+…+d1+d2+…+dn,也就是nd1+(n-1)d2+…+dn;那么我们只要用另一个数组维护一下di*(i-1)就行,到时候输出区间和的时候,就对这个数组求和即可。

#include<iostream>
using namespace std;
const int N=1e5+5;
const int mod=1e9+7;
const int INF=0x3f3f3f3f;
const double EPS=1e-6;
typedef long long ll;
#define IOS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#define int long long
int a[N],d[N],sum1[N],sum2[N];
int n,q;
int lowbit(int x)
{
    return x&-x;
}
void add(int x,int k)
{
    for(int i=x;i<=n;i+=lowbit(i))
    {
        sum1[i]+=k;
        sum2[i]+=k*(x-1);
    }
}
int sum(int x)
{
    int s=0;
    for(int i=x;i;i-=lowbit(i))
    {
        s+=x*sum1[i]-sum2[i];
    }
    return s;
}
signed main()
{
    IOS;
    //freopen("","r",stdin);
    //freopen("","w",stdout);
    cin>>n>>q;
    for(int i=1;i<=n;i++)
    {
        cin>>a[i];
        d[i]=a[i]-a[i-1];
        add(i,d[i]);
    }
    while(q--)
    {
        char ch;
        cin>>ch;
        if(ch=='Q')
        {
            int x,y;
            cin>>x>>y;
            cout<<sum(y)-sum(x-1)<<endl;
        }
        else
        {
            int x,y,k;
            cin>>x>>y>>k;
            add(x,k);
            add(y+1,-k);
        }
    }
}

发布了93 篇原创文章 · 获赞 9 · 访问量 4204

猜你喜欢

转载自blog.csdn.net/Joker_He/article/details/104272052