1. 程式人生 > 其它 >acwing-802. 區間和

acwing-802. 區間和

假定有一個無限長的數軸,數軸上每個座標上的數都是 0。

現在,我們首先進行 n 次操作,每次操作將某一位置 x 上的數加 c。

接下來,進行 m 次詢問,每個詢問包含兩個整數 l 和 r,你需要求出在區間 [l,r] 之間的所有數的和。

輸入格式

第一行包含兩個整數 n 和 m。

接下來 n 行,每行包含兩個整數 x 和 c。

再接下來 m 行,每行包含兩個整數 l 和 r。

輸出格式

共 m 行,每行輸出一個詢問中所求的區間內數字和。

資料範圍

−10^9≤ x ≤10^9,
1≤ n,m ≤10^5,
−10^9≤ l≤r ≤10^9,
−10000≤ c ≤10000

輸入樣例:

3 3
1 2
3 6
7 5
1 3
4 6
7 8

輸出樣例:

8
0
5

方法一:

被難住了..不熟悉C++ STL,故知道離散化和排序但不會去重 23333

分析:

  1. 數軸是無限長的,所以x∈R,所以不能開個陣列並且下標代表x,而輸入的x個數是有限的,所以可以將其離散化,比如1 20 100 12312對映到陣列下標1 2 3 4
  2. 這題要進行有序的離散化,也就是離散化之後用於對映的陣列儲存的x是有序的,便於後面使用二分搜尋
  3. 最後利用字首和進行求區間和操作

做法:

  1. 將輸入資料全部讀入,alls用來對映 ( 陣列下標, x ),即先把所有x讀入alls,再用STL函式排序和去重得到正確的對映資料
  2. nums儲存每個x上對應的c
  3. 最後字首和,即區間和

補充:

  1. find()函式返回大於x的最小元素下標(當x大於最大元素,返回最大元素下標)
  2. 核心在於理解離散化
#include <bits/stdc++.h>

using namespace std;

typedef pair<int, int> PII;
int n, m;
int nums[300010];

vector<int> alls;
vector<PII> add, query;

int find(int x) {
    int l = 0, r = alls.size() - 1;
    while (l < r) {
        int mid = (l + r) >> 1;
        if (alls[mid] >= x) r = mid;
        else l = mid + 1;
    }
    return r + 1;
}

int main() {
    scanf("%d%d", &n, &m);
    for (int i = 0; i < n; i++) {
        int x, c;
        scanf("%d%d", &x, &c);
        alls.push_back(x);
        add.emplace_back(x, c);
    }
    for (int i = 0; i < m; i++) {
        int l, r;
        scanf("%d%d", &l, &r);
        alls.push_back(l);
        alls.push_back(r);
        query.emplace_back(l, r);
    }

    // 排序+去重
    sort(alls.begin(), alls.end());
    alls.erase(unique(alls.begin(), alls.end()), alls.end());

    // 處理插入
    for (auto item: add) {
        int x = find(item.first);
        nums[x] += item.second;
    }

    // 字首和
    for (int i = 1; i <= alls.size(); i++) nums[i] += nums[i-1];

    for (int i = 0; i < m; i++) {
        int l = find(query[i].first);
        int r = find(query[i].second);
        printf("%d\n", nums[r] - nums[l-1]);
    }
}