离散化的一道很经典的题

  1. 区间和
    题目
    提交记录
    讨论
    题解
    视频讲解

假定有一个无限长的数轴,数轴上每个坐标上的数都是 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];

vectorstu;
vectoraoi,aio;

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;

}

posted @ 2024-10-13 00:14  fafatadie  阅读(11)  评论(0编辑  收藏  举报