【ACwing】802.区间和/离散化/二分

这篇博客介绍了如何利用离散化和前缀和技巧解决一个数学问题:在无限数轴上进行加法操作和区间求和查询。首先对操作位置和查询区间进行排序去重,然后执行加法操作并计算前缀和,最后通过前缀和快速回答区间和查询。文章还提供了二分查找的模板和完整的C++代码实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题面

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

现在,我们首先进行 n 次操作,每次操作将某一位置x上的数加c。

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

输入格式

第一行包含两个整数n和m。

接下来 n 行,每行包含两个整数x和c。

再接下里 m 行,每行包含两个整数l和r。

输出格式

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

数据范围

−109≤x≤109−109≤x≤109,
1≤n,m≤1051≤n,m≤105,
−109≤l≤r≤109−109≤l≤r≤109,
−10000≤c≤10000−10000≤c≤10000

输入样例:

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

输出样例:

8
0
5

【题解】:
1.观察数据,发现数据给的很大,但是数量却没有很多,所以要进行离散化。
2.目前我对离散化的理解是:用一个vector去存下原来的数,而且要排序去重。之后要找这个值的话就可以写一个findd数组用二分去找。
3.排序和去重可以用STL来做:
(1)排序:sort(xxxx.begin(),xxxx.end())
(2)去重:用erase加上unique,erase就是给出两指针,删掉他们之间的所有的数;unique就是针对排好顺序的一组数(一般),把不重复的往前排,并且返回的是不重复的最后一个元素的后面一个位置。
4.这个题目的话,把加数和查询的位置存下来,之后去重排序,然后再实行加数的操作,完了之后求一下前缀和,之后的查询前缀和来完成就可。

二分的模板

顺便记录一下二分的模板(y神的模板):
算法思路:
假设目标值在闭区间[l, r]中, 每次将区间长度缩小一半,当l = r时,我们就找到了目标值。

版本1
当我们将区间[l, r]划分成[l, mid]和[mid + 1, r]时,其更新操作是r = mid或者l = mid + 1;,计算mid时不需要加1。

C++ 代码模板:

int bsearch_1(int l, int r)
{
    while (l < r)
    {
        int mid = l + r >> 1;
        if (check(mid)) r = mid;
        else l = mid + 1;
    }
    return l;
}

版本2
当我们将区间[l, r]划分成[l, mid - 1]和[mid, r]时,其更新操作是r = mid - 1或者l = mid;,此时为了防止死循环,计算mid时需要加1。

C++ 代码模板:

int bsearch_2(int l, int r)
{
    while (l < r)
    {
        int mid = l + r + 1 >> 1;
        if (check(mid)) l = mid;
        else r = mid - 1;
    }
    return l;
}

作者:yxc
链接:https://www.acwing.com/blog/content/31/

代码

#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int maxn=1000005;
typedef pair<int,int> p;

int a[maxn],sum[maxn];
p arr[maxn],qury[maxn];
vector<int> alls;
int findd(int x)
{
	int l=0;
	int 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 l,r; 
	int n,m;
	cin>>n>>m;
	
	for(int i=0;i<n;i++)
	{
		cin>>arr[i].first>>arr[i].second;
		alls.push_back(arr[i].first);		
	} 
	for(int i=0;i<m;i++)
	{
		cin>>l>>r;
		qury[i].first=l;
		qury[i].second=r;
		alls.push_back(l);
		alls.push_back(r);
	}
	sort(alls.begin(),alls.end());
	alls.erase(unique(alls.begin(),alls.end()),alls.end());
	for(int i=0;i<n;i++)
	{
		int x=findd(arr[i].first);
		a[x]+=arr[i].second;
	}
	for(int i=1;i<=alls.size();i++)
	{
		sum[i]=sum[i-1]+a[i];
	//	cout<<" i="<<i<<"  sum[i]="<<sum[i]<<endl;
	}
	
	for(int i=0;i<m;i++)
	{
		l=findd(qury[i].first);
		r=findd(qury[i].second);
		cout<<sum[r]-sum[l-1]<<endl;
	}
	return 0;
} 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值