题目链接

小苯的数组查询(二)

题目描述

给定一个长度为 的数组,需要处理 次操作。操作分为两种:

  1. 1 type x:修改操作。如果 ,则将数组中所有奇数都加上 ;如果 ,则将数组中所有偶数都加上
  2. 2:查询操作。查询并输出当前数组所有元素的总和。

思路分析

直接模拟每次更新操作,即遍历整个数组对符合奇偶性条件的元素进行修改,时间复杂度为 。对于 次操作,总时间复杂度为 ,这在 较大时会超时。

我们可以换一个角度,不去维护数组中的每一个具体值,而是维护整个数组的宏观统计信息。具体来说,我们只需要维护三个量:

  • :数组中所有元素的总和。
  • :数组中奇数的个数。
  • :数组中偶数的个数。

初始化

在处理操作前,我们首先遍历一次原始数组,用 的时间计算出这三个量的初始值。

处理操作

  • 查询操作 (2): 直接输出我们维护的 即可,时间复杂度为

  • 修改操作 (1 type x):

    1. 更新总和:

      • 如果 (给奇数加 ),那么总和增加的值等于奇数的个数乘以 ,即
      • 如果 (给偶数加 ),那么总和增加的值等于偶数的个数乘以 ,即
    2. 更新奇偶数个数:

      • 一个数加上 后,其奇偶性是否改变,完全取决于 的奇偶性。
      • 如果 是偶数,那么 奇数+偶数=奇数偶数+偶数=偶数。数字的奇偶性不变, 均不改变。
      • 如果 是奇数,那么 奇数+奇数=偶数偶数+奇数=奇数。数字的奇偶性会发生反转。
        • 对于 的操作,所有奇数都变成了偶数。因此,我们将 的值加到 上,然后将 置为
        • 对于 的操作,所有偶数都变成了奇数。因此,我们将 的值加到 上,然后将 置为

通过这种方式,每次修改操作都可以在 的时间内完成。

代码

#include <iostream>
#include <vector>
#include <numeric>

using namespace std;

void solve() {
    int n;
    long long q;
    cin >> n >> q;

    long long count_odd = 0;
    long long count_even = 0;
    long long sum_total = 0;

    for (int i = 0; i < n; ++i) {
        long long val;
        cin >> val;
        if (val % 2 == 0) {
            count_even++;
        } else {
            count_odd++;
        }
        sum_total += val;
    }

    for (int i = 0; i < q; ++i) {
        int type;
        cin >> type;
        if (type == 1) {
            int op_type;
            long long x;
            cin >> op_type >> x;
            if (op_type == 1) { // 给奇数加x
                sum_total += count_odd * x;
                if (x % 2 != 0) { // x是奇数,奇偶性反转
                    count_even += count_odd;
                    count_odd = 0;
                }
            } else { // 给偶数加x
                sum_total += count_even * x;
                if (x % 2 != 0) { // x是奇数,奇偶性反转
                    count_odd += count_even;
                    count_even = 0;
                }
            }
        } else {
            cout << sum_total << endl;
        }
    }
}

int main() {
    // 为处理多组测试用例(虽然本题只有一组,但这是个好习惯)
    // ios_base::sync_with_stdio(false);
    // cin.tie(NULL);
    solve();
    return 0;
}
import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        
        int n = sc.nextInt();
        int q = sc.nextInt();

        long countOdd = 0;
        long countEven = 0;
        long sumTotal = 0;

        for (int i = 0; i < n; i++) {
            long val = sc.nextLong();
            if (val % 2 == 0) {
                countEven++;
            } else {
                countOdd++;
            }
            sumTotal += val;
        }

        for (int i = 0; i < q; i++) {
            int type = sc.nextInt();
            if (type == 1) {
                int opType = sc.nextInt();
                long x = sc.nextLong();
                if (opType == 1) { // 给奇数加x
                    sumTotal += countOdd * x;
                    if (x % 2 != 0) { // x是奇数,奇偶性反转
                        countEven += countOdd;
                        countOdd = 0;
                    }
                } else { // 给偶数加x
                    sumTotal += countEven * x;
                    if (x % 2 != 0) { // x是奇数,奇偶性反转
                        countOdd += countEven;
                        countEven = 0;
                    }
                }
            } else {
                System.out.println(sumTotal);
            }
        }
    }
}
import sys

def solve():
    n, q = map(int, sys.stdin.readline().split())
    arr = list(map(int, sys.stdin.readline().split()))

    count_odd = 0
    count_even = 0
    sum_total = 0

    for val in arr:
        if val % 2 == 0:
            count_even += 1
        else:
            count_odd += 1
        sum_total += val

    for _ in range(q):
        line = list(map(int, sys.stdin.readline().split()))
        op_type = line[0]

        if op_type == 1:
            type_val, x = line[1], line[2]
            if type_val == 1:  # 给奇数加x
                sum_total += count_odd * x
                if x % 2 != 0:
                    count_even += count_odd
                    count_odd = 0
            else:  # 给偶数加x
                sum_total += count_even * x
                if x % 2 != 0:
                    count_odd += count_even
                    count_even = 0
        else:
            print(sum_total)

solve()

算法及复杂度

  • 算法:宏观状态维护/计数
  • 时间复杂度。其中 用于初始化统计变量,之后每次操作的复杂度为 ,总共 次操作。
  • 空间复杂度(Python代码中为 用于存储初始数组,但可以优化为 )。我们只需要常数个变量来维护数组的统计信息,而无需存储整个数组。