牛客小白月赛5 I 区间

链接:https://www.nowcoder.com/acm/contest/135/I
来源:牛客网
 

题目描述

    Apojacsleam喜欢数组。

    他现在有一个n个元素的数组a,而他要对a[L]-a[R]进行M次操作:

        操作一:将a[L]-a[R]内的元素都加上P

        操作二:将a[L]-a[R]内的元素都减去P

    最后询问a[l]-a[r]内的元素之和?

    请认真看题干及输入描述。

输入描述:

输入共M+3行:

第一行两个数,n,M,意义如“题目描述”

第二行n个数,描述数组。

第3-M+2行,共M行,每行四个数,q,L,R,P,若q为1则表示执行操作2,否则为执行操作1

第4行,两个正整数l,r

输出描述:

一个正整数,为a[l]-a[r]内的元素之和

示例1

输入

复制

10 5
1 2 3 4 5 6 7 8 9 10
1 1 5 5
1 2 3 6
0 2 5 5 
0 2 5 8
1 4 9 6
2 7

输出

复制

23

说明

 

题意:区间修改,区间询问的模版题

思路:模版题,但是不知道为何初始存的时候那里出错了,所以用了一个操作记录一下,输出即可

//
//  main.cpp
//  区间
//
//  Created by dhl on 2018/7/22.
//  Copyright © 2018年 dhl. All rights reserved.
//

#include <iostream>
using namespace std;
const int maxn = 1e6 + 5;
#define ll long long
int n, m;
ll a[maxn], sum1[maxn], sum2[maxn];
void add(ll p, ll x){
    for(ll i = p; i <= n; i += i & -i) {
        sum1[i] += x;
        sum2[i] += x * p;
    }
}
void range_add(ll l, ll r, ll x){
    add(l, x);
    add(r + 1, -x);
}
ll ask(ll p){
    ll res = 0;
    for(ll i = p; i; i -= i & -i)
        res += (p + 1) * sum1[i] - sum2[i];
    return res;
}
ll range_ask(ll l, ll r){
    return ask(r) - ask(l - 1);
}
int main(int argc, const char * argv[]) {
    ios::sync_with_stdio(false);
    cin >> n >> m;
    a[0] = 0;
    for (int i = 1; i <= n; i ++) {
        cin >> a[i];
        sum1[i] = a[i] - a[i - 1];
        sum2[i] = sum1[i] * i;
    }
    for (int i = 1; i <= n; i ++) {
        a[i] -= range_ask(i, i);
    }
    for (int i = 1; i <= m; i ++) {
        int q, l, r, p;
        cin >> q >> l >> r >> p;
        if (q == 1)
            p *= -1;
        range_add(l, r, p);
    }
    int l, r;
    cin >> l >> r;
    for (int i = 1; i <= n; i ++) {
        a[i] += range_ask(i, i);
    }
    ll ans = 0;
    for (int i = l; i <= r; i ++) {
        ans += a[i];
    }
    cout << ans << endl;
    return 0;
}
//10 5
//1 2 3 4 5 6 7 8 9 10
//1 1 5 5
//1 2 3 6
//0 2 5 5
//0 2 5 8
//1 4 9 6
//2 7

刚才看到学长写的,对于树状数组又有了新的认识

用sum来代表差分数组,对l-r的区间修改就是对sum[l]+=x,sum[r + 1]-=x,sum的前i项和就是a[i]的值(深刻体会)

为什么值改变sum[l]的值,a[i]也会跟着改变呢,应sum[l]改变,意味着a[i]与a[l-1]的差值多了x,而sum[l +1] - sum[r]的值都不变,就是a[l+1]-a[r]的值的差值不变(因为他们增加了相同的x),而sum[r+1]的值减小,就代表着a[r] 值变大而a[r+1]不变,所以差值就减小了。而计算的时候,sum[i]的前i项和,就相当与a[i]的变化量在与a[i]相加,就得到变化后的a[i]的值

//
//  main.cpp
//  区间2
//
//  Created by dhl on 2018/7/23.
//  Copyright © 2018年 dhl. All rights reserved.
//

#include <iostream>
using namespace std;
const int maxn = 20;
int a[maxn], sum[maxn];
int main(int argc, const char * argv[]) {
    int n, m;
    cin >> n >> m;
    for (int i = 1; i <= n; i ++)
        cin >> a[i];
    for (int i = 1; i <= m; i ++) {
        int q, l, r, w;
        cin >> q >> l >> r >> w;
        if (q!= 1)
            sum[r + 1] -=w, sum[l] += w;//l-r区间的改变
        else
            sum[r + 1] += w, sum[l] -= w;
    }
    for (int i = 1; i <= n; i ++) {
        sum[i] += sum[i - 1];//sum之和就是a[i]的变化量
        a[i] += sum[i];//相加得到a[i]变化后的值
    }
    int l, r;
    cin >> l >> r;
    long long ans = 0;
    for (int i = l; i <= r; i ++)
        ans += a[i];
    cout << ans << endl;
    return 0;
}

这里的sum是表示的是a[i]的变化值,如果sum一开始就表示a的差分数组

//
//  main.cpp
//  区间2
//
//  Created by dhl on 2018/7/23.
//  Copyright © 2018年 dhl. All rights reserved.
//

#include <iostream>
using namespace std;
const int maxn = 1e6 + 5;
int a[maxn], sum[maxn];
int main(int argc, const char * argv[]) {
    int n, m;
    cin >> n >> m;
    for (int i = 1; i <= n; i ++) {
        cin >> a[i];
        sum[i] = a[i] - a[i - 1];
    }
    for (int i = 1; i <= m; i ++) {
        int q, l, r, w;
        cin >> q >> l >> r >> w;
        if (q!= 1)
            sum[r + 1] -=w, sum[l] += w;//l-r区间的改变
        else
            sum[r + 1] += w, sum[l] -= w;
    }
    for (int i = 1; i <= n; i ++) {
        a[i] = sum[i] += sum[i - 1];
    }
    int l, r;
    cin >> l >> r;
    long long  ans = 0;
    for (int i = l; i <= r; i ++)
        ans += a[i];
    cout << ans << endl;
    return 0;
}

猜你喜欢

转载自blog.csdn.net/henu_jizhideqingwa/article/details/81160096
今日推荐