区间和(离散化)

假定有一个无限长的数轴,数轴上每个坐标上的数都是 00。

现在,我们首先进行 nn 次操作,每次操作将某一位置 xx 上的数加 cc。

接下来,进行 mm 次询问,每个询问包含两个整数 ll 和 rr,你需要求出在区间 [l,r][l,r] 之间的所有数的和。

输入格式

第一行包含两个整数 nn 和 mm。

接下来 nn 行,每行包含两个整数 xx 和 cc。

再接下来 mm 行,每行包含两个整数 ll 和 rr。

输出格式

共 mm 行,每行输出一个询问中所求的区间内数字和。

数据范围

109x109−109≤x≤109,
1n,m1051≤n,m≤105,
109lr109−109≤l≤r≤109,
10000c10000−10000≤c≤10000

输入样例:

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

输出样例:

8
0
5
解释:离散化是在值域特别大的时候,但个数n不是很大的时候用。怎么说就是假定在一根数轴上,范围很大(那肯定是不能开那么大的数组了),把相应的坐标一一映射到连续的坐标上
缩短了空间。这个题一看最基本的思路是用前缀和,但是数据范围太大,应该离散化各个点的坐标。
复制代码
//前缀和板子:
const int N=10010;
int a[N],s[N];//分别存单个元素和求和的值 
int main(){
    int n;
    for(int i=1;i<=n;i++)//这里从1开始,避免了下标为负数的情况
    {
        s[i]=s[i-1]+a[i]//前缀和的初始化 
    } 
    int l,r;
    cout<<s[r]-s[l-1]<<endl;
} 
复制代码

离散化的本质是把超级大的不连续的坐标一一映射到连续的坐标,这里用二分来写,前提要先排序和去重

复制代码
//二分板子:
int l,r;
while(l<r)
{
    int mid=l+r>>1;
    if(q[mid]>=x) r=mid;
    else l=mid+1;
} 
return l;

int l,r;
while(l<r)
{
    int mid=l+r+1;
    if(q[mid]<=x) l=mid;
    else r=mid-1;
}
return l;
复制代码

离散化的二分:

复制代码
sort(alls.begin(),alls.end());
alls.erase(unique(alls.begin(),alls.end()),alls.end());

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;//这一步就是把坐标映射到下标从1开始 
}
复制代码

总代码:

复制代码
#include <iostream>
#include <vector>
#include <algorithm>

using namespace std;

typedef pair<int, int> PII;

const int N = 300010;

int n, m;
int a[N], s[N];

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()
{
    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)//新写法,遍历add中所有元素 
    {
        int x = find(item.first);//一一映射到连续的下标 
        a[x] += item.second;//在新映射的下标上进行操作 
    }

    // 预处理前缀和
    for (int i = 1; i <= alls.size(); i ++ ) s[i] = s[i - 1] + a[i];

    // 处理询问
    for (auto item : query)
    {
        int l = find(item.first), r = find(item.second);//依然处理下标 
        cout << s[r] - s[l - 1] << endl; //根据新的下标和值的关系来求前缀和 
    }
    return 0;
}
复制代码

 

 
posted @   小志61314  阅读(101)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具
点击右上角即可分享
微信分享提示