题目链接

题目描述

份资源,编号为 1 到 ,初始均处于未上锁状态。现在共有 次操作,每次给定一个编号

  • 若编号为 的资源未上锁,则为其上锁;
  • 否则,解除其锁,使其回到未上锁状态。

每次操作后,牛牛希望分别统计区间 中“可访问”(即未上锁)资源的数量。

输入:

  • 第一行一个整数 代表数据组数。
  • 每组数据第一行四个整数:
  • 此后 行,每行一个整数 ,表示操作的资源编号。

输出:

  • 对于每次操作,新起一行输出两个整数,分别表示区间 中可访问资源的数量。

解题思路

这是一个需要高效处理区间查询和单点更新的问题。由于操作次数 可能很大,如果在每次操作后都重新遍历区间来计数(),总时间复杂度将是 ,可能会超时。因此,我们需要一种更高效的增量计算方法。

我们可以维护两个计数器,分别对应两个目标区间中未上锁资源的数量。每次操作只影响一个资源,我们可以根据这个资源的状态变化和它所在的位置,来动态更新这两个计数器。

算法步骤如下:

  1. 状态初始化

    • 创建一个大小为 的布尔数组 ,全部初始化为 false,表示所有资源初始都未上锁。
    • 初始化两个计数器:
      • (区间 的未上锁数量) =
      • (区间 的未上锁数量) =
  2. 处理每次操作:对于每次给定的资源编号

    • 检查当前状态:查看 的值。
    • ** case 1: 资源即将被上锁** (即 false):
      • 如果 在区间 内 (即 ),则该区间内未上锁资源数减 1,故
      • 如果 在区间 内 (即 ),则该区间内未上锁资源数减 1,故
    • ** case 2: 资源即将被解锁** (即 true):
      • 如果 ,则
      • 如果 ,则
    • 更新状态:翻转资源 的锁定状态,
    • 输出结果:输出更新后的

这种方法将每次操作的复杂度降到了 ,可以高效地解决问题。

代码

#include <iostream>
#include <vector>

using namespace std;

void solve() {
    int n, m, r1, l2;
    cin >> n >> m >> r1 >> l2;
    
    // is_locked[i] 为 true 表示资源 i 已上锁
    vector<bool> is_locked(n + 1, false);
    // count1: 区间 [1, r1] 中未上锁的资源数
    int count1 = r1;
    // count2: 区间 [l2, n] 中未上锁的资源数
    int count2 = n - l2 + 1;

    for (int i = 0; i < m; ++i) {
        int x;
        cin >> x;

        if (is_locked[x]) {
            // 当前是上锁状态,操作后解锁
            is_locked[x] = false;
            // 检查 x 是否在区间 [1, r1] 内
            if (x >= 1 && x <= r1) {
                count1++;
            }
            // 检查 x 是否在区间 [l2, n] 内
            if (x >= l2 && x <= n) {
                count2++;
            }
        } else {
            // 当前是未上锁状态,操作后上锁
            is_locked[x] = true;
            if (x >= 1 && x <= r1) {
                count1--;
            }
            if (x >= l2 && x <= n) {
                count2--;
            }
        }
        cout << count1 << " " << count2 << endl;
    }
}

int main() {
    // 处理多组测试数据
    int t;
    cin >> t;
    while (t--) {
        solve();
    }
    return 0;
}
import java.util.Scanner;

public class Main {
    public static void solve(Scanner sc) {
        int n = sc.nextInt();
        int m = sc.nextInt();
        int r1 = sc.nextInt();
        int l2 = sc.nextInt();

        // isLocked[i] 为 true 表示资源 i 已上锁
        boolean[] isLocked = new boolean[n + 1]; // 默认全为 false
        // count1: 区间 [1, r1] 中未上锁的资源数
        int count1 = r1;
        // count2: 区间 [l2, n] 中未上锁的资源数
        int count2 = n - l2 + 1;

        for (int i = 0; i < m; i++) {
            int x = sc.nextInt();
            
            if (isLocked[x]) {
                // 当前是上锁状态,操作后解锁
                isLocked[x] = false;
                // 检查 x 是否在区间 [1, r1] 内
                if (x >= 1 && x <= r1) {
                    count1++;
                }
                // 检查 x 是否在区间 [l2, n] 内
                if (x >= l2 && x <= n) {
                    count2++;
                }
            } else {
                // 当前是未上锁状态,操作后上锁
                isLocked[x] = true;
                if (x >= 1 && x <= r1) {
                    count1--;
                }
                if (x >= l2 && x <= n) {
                    count2--;
                }
            }
            System.out.println(count1 + " " + count2);
        }
    }
    
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        // 处理多组测试数据
        int t = sc.nextInt();
        while (t-- > 0) {
            solve(sc);
        }
    }
}
import sys
input=sys.stdin.readline

# python 代码请提交到 pypy3

def solve():
    # 读取一行并解析为整数
    n, m, r1, l2 = map(int, input().split())
    
    # is_locked[i] 为 True 表示资源 i 已上锁
    is_locked = [False] * (n + 1)
    # count1: 区间 [1, r1] 中未上锁的资源数
    count1 = r1
    # count2: 区间 [l2, n] 中未上锁的资源数
    count2 = n - l2 + 1

    for _ in range(m):
        x = int(input())
        
        if is_locked[x]:
            # 当前是上锁状态,操作后解锁
            is_locked[x] = False
            # 检查 x 是否在区间 [1, r1] 内
            if 1 <= x <= r1:
                count1 += 1
            # 检查 x 是否在区间 [l2, n] 内
            if l2 <= x <= n:
                count2 += 1
        else:
            # 当前是未上锁状态,操作后上锁
            is_locked[x] = True
            if 1 <= x <= r1:
                count1 -= 1
            if l2 <= x <= n:
                count2 -= 1
        
        print(count1, count2)

# 处理多组测试数据
t = int(input())
for _ in range(t):
    solve()

算法及复杂度

  • 算法:模拟、增量计算
  • 时间复杂度: 对于每组测试数据,初始化需要 ,后续 次操作每次都是 ,所以总时间复杂度是
  • 空间复杂度: ,用于存储 个资源的状态。