802. 区间和 【离散化】超详细解析

在这里插入图片描述
https://www.acwing.com/problem/content/804/

本题的数据范围实在太大,用哈希表做不出来,但是你会发现数轴上的数字是离散的,就是数轴上的数不是一个挨着一个的,数轴上的数并不是特别多。那么我们就可以将数轴上的点映射到一个挨着的数组里。

本解析一步步的求出结果,且根据案例。 故边看案例边看代码使用效果最好。

总共需要的数组

  • add : 保存真实的下标和相应的值
  • alls : 用来保存真实的下标和想象的下标的映射关系
  • query : 用来保存我们查询的左右两个端点
  • a : 保存想象的坐标所对应的值
  • s: 保存想象的坐标所对应的值的前缀和

第一步: 输入数轴上所对应的值

for(int i=0;i<n;i++)
{
	int index,x; cin>>index>>x;
	add.push_back({index,x});//index 是我们真实的下标 x是数值
	alls.push_back(index);// 将真实的下标和我们想象的坐标建立映射关系
}

在这里插入图片描述
第二步: 输入我们的查询的区间

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);
	}

第三步: 将虚拟的坐标排序并去重
为啥去重:
是因为当我们输入
3 5
3 6
即给数轴上3的点加5 再加 6时。此时我们的坐标映射表里有了两个3 3 但其实它们对应的是同一个坐标。
故需要去重,排序。

 sort(alls.begin(), alls.end());//排序
 alls.erase(unique(alls), 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 l+1;//  因为要求前缀和,故下标从1开始方便,不用额外的再处理边界。
}
for(int i=0;i<add.size();i++)
{
		int x=find(add[i].first);
		a[x]+=add[i].second;
} 

在这里插入图片描述

此时方框中的数,就是该位置所对应的值。
注意那些值为0的坐标是区间的边界,因为没有值的大小故为0。引入它们的目的是为了方便求前缀和。

最后一步: 求前缀和,根据我们的查询的区间来输出区间的和

for(int i=1;i<=alls.size();i++) s[i]=s[i-1]+a[i];
	
for(int i=0;i<query.size();i++)
{
	int l=find(query[i].first),r=find(query[i].second);
	cout<<s[r]-s[l-1]<<endl;
}

总的代码:

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<vector>
#include<map>
using namespace std;
typedef pair<int,int> PII;
const int N=300010;
int a[N],s[N];
vector<int> alls;
vector<PII> add,query;

vector<int>:: iterator unique(vector<int> &a)
{
    int j = 0;
    for(int i = 0; i < a.size(); i ++)
        if(!i || a[i] != a[i - 1])
            a[j ++ ] = a[i];
    return a.begin() + j;
}

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 l+1;
}
int main(void)
{
	int n,m; cin>>n>>m;
	for(int i=0;i<n;i++)
	{
		int index,x; cin>>index>>x;
		add.push_back({index,x});
		alls.push_back(index);
	}
	
	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), alls.end());//去重(坐标)
	 
	for(int i=0;i<add.size();i++)
	{
		int x=find(add[i].first);
		a[x]+=add[i].second;
	} 
	
	for(int i=1;i<=alls.size();i++) s[i]=s[i-1]+a[i];
	
	for(int i=0;i<query.size();i++)
	{
		int l=find(query[i].first),r=find(query[i].second);
		cout<<s[r]-s[l-1]<<endl;
	}
	return 0;
}
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;

typedef pair<int, int> PII;
const int N = 300010;
int a[N], s[N];
int n, m;

vector<int> alls;//坐标
vector<PII> add, query;//  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;
}
vector<int>:: iterator unique(vector<int> &a)
{
    int j = 0;
    for(int i = 0; i < a.size(); i ++)
        if(!i || a[i] != a[i - 1])
            a[j ++ ] = a[i];
    return a.begin() + j;
}

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), alls.end());//去重(坐标)

    for(auto item : 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;
}

#include<cstdio>
#include<iostream>
#include<vector>
#include<map>
#include<algorithm>
using namespace std;
typedef pair<int,int> PII;
map<int,int>mp,vis;// mp 映射值, vis 去重
int n,m;
vector<PII>ans;// 
vector<int>all,sum;//总的下标
int find(int x)
{
    int l=0,r=all.size()-1;
    while(l<r)
    {
        int mid=l+r>>1;
        if(x<=all[mid])  r=mid;
        else l=mid+1;
    }
    return r+1;
}
int main(void)
{
    cin>>n>>m;
    while(n--)
    {
        int x,c; cin>>x>>c; mp[x]+=c;
        if(!vis[x]) all.push_back(x),vis[x]++;
    }
    while(m--)
    {
        int l,r;  cin>>l>>r;
        ans.push_back({l,r});
        if(!vis[l]) all.push_back(l),vis[l]++;
        if(!vis[r]) all.push_back(r),vis[r]++;
    }
    sort(all.begin(),all.end());
    sum.push_back(0);
    for(int i=0;i<all.size();i++)  sum.push_back(mp[all[i]]);
    for(int i=1;i<sum.size();i++) sum[i]+=sum[i-1];
    for(int i=0;i<ans.size();i++)
    {
        int l=find(ans[i].first);
        int r=find(ans[i].second);
        cout<<sum[r]-sum[l-1]<<endl;
    }
    return 0;
}
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<map>
#include<vector>
using namespace std;
typedef pair<int,int> PII;
vector<int>sum,all;
vector<PII>ve;
map<int,int>mp,vis;
int n,m;
int find(int x)
{
    int l=0,r=all.size()-1;
    while(l<r)
    {
        int mid=l+r>>1;
        if(all[mid]>=x) r=mid;
        else l=mid+1;
    }
    return r+1;
}
int main(void)
{
    cin>>n>>m;
    while(n--)
    {
        int x,c; cin>>x>>c;
        mp[x]+=c;
        if(!vis[x]) all.push_back(x),vis[x]++;
    }
    while(m--)
    {
        int l,r; cin>>l>>r;
        ve.push_back({l,r});
        if(!vis[l]) all.push_back(l),vis[l]++;
        if(!vis[r]) all.push_back(r),vis[r]++;
    }
    sort(all.begin(),all.end());
    sum.push_back(0);
    for(int i=0;i<all.size();i++) sum.push_back(mp[all[i]]),sum[i+1]+=sum[i];
    for(int i=0;i<ve.size();i++)
    {
        int l=find(ve[i].first);
        int r=find(ve[i].second);
        cout<<sum[r]-sum[l-1]<<endl;
    }
    return 0;
}