離散化的步驟:
1、去重---數列中可能存在重複元素
2、二分查找---算出x離散化的值
vector<int> alls; // 存儲所有待離散化的值
sort(alls.begin(), alls.end()); // 將所有值排序
alls.erase(unique(alls.begin(), alls.end()), alls.end()); // 去掉重複元素
// 二分求出x對應的離散化的值
int find(int x) // 找到第一個大於等於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; // 映射到1, 2, ...n
}
例題:區間和
假定有一個無限長的數軸,數軸上每個座標上的數都是0。
現在,我們首先進行 n 次操作,每次操作將某一位置x上的數加c。
近下來,進行 m 次詢問,每個詢問包含兩個整數l和r,你需要求出在區間[l, r]之間的所有數的和。
輸入格式
第一行包含兩個整數n和m。
接下來 n 行,每行包含兩個整數x和c。
再接下里 m 行,每行包含兩個整數l和r。
輸出格式
共m行,每行輸出一個詢問中所求的區間內數字和。
數據範圍
輸入樣例:
3 3
1 2
3 6
7 5
1 3
4 6
7 8
輸出樣例:
8
0
5
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
const int N = 3e5+10;
int A[N],sum[N];
vector<int>alls;
vector<pair<int,int> >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(){
int n,m;
cin>>n>>m;
for(int i=0;i<n;i++){
int x,c;
cin>>x>>c;
add.push_back({x,c});
alls.push_back(x);
}
for(int i=0;i<m;i++){
int l,r;
cin>>l>>r;
query.push_back({l,r});
alls.push_back(l);
alls.push_back(r);
}
//去重
sort(alls.begin(),alls.end());
alls.erase(unique(alls.begin(),alls.end()),alls.end());
//處理插入
for(auto item:add){
int x=Find(item.first);
A[x]+=item.second;
}
//預處理前綴和
for(int i=1;i<=alls.size();i++)
sum[i]=sum[i-1]+A[i];
//處理詢問
for(auto item:query){
int l=Find(item.first),r=Find(item.second);
cout<<sum[r]-sum[l-1]<<endl;
}
return 0;
}