- 區間和
題目
提交記錄
討論
題解
影片講解
假定有一個無限長的數軸,數軸上每個座標上的數都是 0
。
現在,我們首先進行 n
次操作,每次操作將某一位置 x
上的數加 c
。
接下來,進行 m
次詢問,每個詢問包含兩個整數 l
和 r
,你需要求出在區間 [l,r]
之間的所有數的和。
輸入格式
第一行包含兩個整數 n
和 m
。
接下來 n
行,每行包含兩個整數 x
和 c
。
再接下來 m
行,每行包含兩個整數 l
和 r
。
輸出格式
共 m
行,每行輸出一個詢問中所求的區間內數字和。
資料範圍
−109≤x≤109
,
1≤n,m≤105
,
−109≤l≤r≤109
,
−10000≤c≤10000
輸入樣例:
3 3
1 2
3 6
7 5
1 3
4 6
7 8
輸出樣例:
8
0
5
離散化的含義便是對映,把有關的陣列下標對映為自然數0,1,2,3....或者1,2,3,4,5....,首先使用離散化的前提的條件便是值域跨度很大,但題目的輸入和輸出中牽扯到的數字下標沒有這麼大。例如本題:
值域範圍為:1e9的範圍,但本體在輸入時先給某個下標加值,n最多便是1e5,而m每次詢問有兩個下標(索引),m的範圍是1e5,故m * 2 + n 的範圍便是3e5 + 10(這個10是為了防止陣列越界的問題)。當然,如果資料範圍什麼時候變小了,大致是一個2*1e5的範圍,就可以用我們常用到的字首和來求解,這個離散化可以完美的使用我們的陣列,保證所有的下標都與題目有聯絡。
附上c++程式碼:
include
include
include
using namespace std;
const int N = 300010;
typedef pair<int,int> PII;
int n,m;
int a[N],b[N];
vector
vector
int find(int x)
{
int l = 0,r = stu.size() - 1;
while(l < r)
{
int mid = l + r >> 1;
if(stu[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,y;
cin >> x >> y;
stu.push_back(x);
aoi.push_back({x,y});
}
for(int j = 0;j < m;j ++)
{
int l,r;
cin >> l >> r;
stu.push_back(l);
stu.push_back(r);
aio.push_back({l,r});
}
sort(stu.begin(),stu.end());
stu.erase(unique(stu.begin(),stu.end()),stu.end());
for(auto boy:aoi)
a[find(boy.first)] += boy.second;
for(int i = 1;i <= stu.size(); i ++) b[i] = b[i-1] + a[i];
for(auto riu:aio)
printf("%d\n" , b[find(riu.second)] - b[find(riu.first) - 1]);
return 0;
}