区间问题(差分数组前缀和)

Description
Uncle-lu现在有一个长度为n的序列,淘气的uncle-lu对这个序列进行了多次的修改,每次修改的方式都是,对该序列的一段区间整体加上一个数。多次修改之后,uncle-lu想知道该序列中的某一些位置的值是多少,聪明的你一定能帮帮他。
Input
第一行为一个正整数n表示该序列的长度
第二行为n个正整数,表示该序列
第三行为一个正整数q表示接下来有q次修改
接下来q行每行3个整数 a b v,其中a,b表示修改的区间[a,b],v表示对该区间中的每个数增加的值。
接下来一行为一个整数p表示接下来有p次询问。
接下来p行每行1个整数 c表示uncle-lu想知道序列中第c位置的值是多少。
Output
输出共p行,每行对应输入的询问,输出经过修改后该位置的值。
Sample Input 1
5
4 3 2 5 1
3
1 3 4
2 4 -1
3 5 2
2
3
2
Sample Output 1
7
6
Hint
对于100%的数据n<10000,q<10000,0 Time Limit
1000MS
Memory Limit
256MB

分析:
本题涉及多次的区间修改,总不能每次区间内有多少个数,就做加法加多少次,这样时间会超限,因此这题可以使用差分数列的思想来求解,使每次修改时间复杂度为常数,使用差分数列后复原序列有两种选择:一种是对差分数列求前缀和得到序列每一项最终的改变量,一种是用差分数列的定义来复原序列a[n]=a[n-1]+d[n]。
两种方法没有本质区别,时间复杂度一样,但是两种方法在使用时有微小区别:使用第一种方法不必去计算原序列的差分d[n]=a[n]-a[n-1],直接把差分数组各项初始化为0,就去记录改变量,记录完后,求出其前缀和就可以得知序列中每一项最终的改变量;第二种方法需要在使用前求出原序列的差分d[n]=a[n]-a[n-1]并赋给差分数组各项,复原序列时不用求差分数组的前缀和,直接按定义式a[n]=a[n-1]+d[n]计算即可。

本题选择第一种方法,第二种方法的代码通过注释给出。

参考代码:

#include

int main()
{
    int n;//序列长度
    scanf("%d",&n);
    int *a=new int[n+1];//序列
    int *d=new int[n+1];//差分数组
    a[0]=d[0]=0;
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&a[i]);
        //第一种方法
        d[i]=0;
        //第二种方法
        //d[i]=a[i]-a[i-1];
    }

    int q;//q次修改
    scanf("%d",&q);
    int l,r,v;//区间端点序号,改变量
    for(int i=0;i<q;i++)//记录改变量
    {
        scanf("%d %d %d",&l,&r,&v);
        d[l]+=v;
        d[r+1]-=v;
    }

    //第一种方法
    for(int i=1;i<=n;i++)//求前缀和并保存在差分数组里
    {
        d[i]+=d[i-1];
    }
    //第二种方法
    //for(int i=1;i<=n;i++)//复原序列
    //{
    //    a[i]=a[i-1]+d[i];
    //}   

    int p,index;//p次询问,询问项的序号
    scanf("%d",&p);
    for(int i=0;i<p;i++)
    {
        scanf("%d",&index);
        //第一种方法
        printf("%d\n",a[index]+d[index]);//复原序列
        //第二种方法
        //printf("%d\n",a[index]);
    }
    return 0;
}

你可能感兴趣的:(算法基础题)