区间和问题——离散化

原题链接:活动 - AcWing

问题简述:

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

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

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

输入格式

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

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

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

输出格式

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

数据范围

−1e9≤x≤1e9,
1≤n,m≤1e5,
−1e9≤l≤r≤1e9,
−10000≤c≤10000−10000≤c≤10000

输入样例:

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

输出样例:

8
0
5

这是一道典型的离散化处理的题目 。

问题一:为什么不能用哈希或者是开个数组存呢?

  很显然不行,因为这道题数据范围实在是太大了,所以但是并不是每个点都用上了,真正有过添加值的点最多不过1e5因此我们需要考虑的就是如何处理这1e5个数了。

  首先,我们需要把所有的数映射到一个数组里面,这样就可以降低时间复杂度,那么如何实现呢?我们可以用一下思路。

原始数组:-1 -2 6 7 6

下标:         1 2 3 4 5

排列:-2 -1 6  6  7

下标: 2  1  3  5 4

重新排列下标并去重:-2 -1  6  7 

下标:                           1  2  3 4  

ok经过上述推到我们手动模拟了离散化,现在我们只需要把给定区间的l和r通过二分找到前缀数组的左右边界就可以得到答案就是前缀和数组a[r]-a[l-1]。

代码实现:

#include<iostream>
#include<bits/stdc++.h>
using namespace std;
const int N=2e5+10;
int s[N],a[N];    
int cnt=1,sz,max1=0,min1=1e9;
int findl(int x)//查询左边界
{
    int ll=1,rr=sz;
      while(ll<rr)
            {
                int mid=(ll+rr)>>1;
                if(s[mid]>=x) rr=mid;
                else ll=mid+1;
            }
    return ll;
}
int findr(int x)//查询右边界
{
     int ll=1,rr=sz;
      while(ll<rr)
            {
                int mid=(ll+rr+1)>>1;
                if(s[mid]<=x) ll=mid;
                else rr=mid-1;
            }
    return ll;
}
int main()
{
    map<int,int> p;//用于储存每次相加后的值
    int n,m;
    cin>>n>>m;

    while(n--) 
    {
        int x,y;
        cin>>x>>y;
        p[x]+=y;
        s[cnt++]=x;
        max1=max(max1,x);//判断左右边界
        min1=min(min1,x);
    }
    sort(s+1,s+cnt+1);
    sz=unique(s+1,s+cnt+1)-(s+1);
    for(int i=1;i<=sz;i++)
    a[i]=a[i-1]+p[s[i]];
    while(m--)
    {
        int l,r;
        cin>>l>>r;
        if(l>max1||r<min1) cout<<0<<endl;//如果该区间内没有加过任何数直接输出0
        else
        {
           int cnt1=findl(l),cnt2=findr(r);
            cout<<a[cnt2]-a[cnt1-1]<<endl;
        }
    }
    return 0;
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值