离散化区间和(acwing)

本文介绍了如何通过离散化技术,特别是使用前缀和数组和下标重写的方法,解决区间和问题。作者对比了两种方法,一种是使用map进行重写,另一种是unordered_map,展示了它们在处理大规模数据时的空间效率和查询性能。
摘要由CSDN通过智能技术生成

首先解释一下什么叫离散化,离散化就是把大而分散的一段段使用到的稀疏区间,整合映射到连续的一段较小的稠密区间里

就拿上面这题来讲,我们要求区间和肯定要用到前缀和数组。我们观察到 下标是[-1e9,1e9],我们没办法开一个1e9的数组,太大了。

再观察,发现其实最多出现3e5个点(n+2*m),3e5的数组我们是可以开出来的,那我们就只关心已经出现过的点,并这些点的下标进行“重新赋值”。

例如有三个数,下标分别为:2,8,1e8。我们就可以将其下标“重写成1,2,3”,达到节省空间的目的。

我自己喜欢用map进行重写,y总用了二分重写,个人觉得我的比较方便且容易理解一些

vector<PII> add_op;
vector<PII> q_op;
vector<int> alls;
int pre[N],a[N];
int find(int x) {
	//查询x在离散化区间里的位置。
	//返回的是x的下标

	int index = 0;
	int l = 0, r = alls.size() - 1;
	while (l <= r) {
		int mid = (l + r) >> 1;
		if (alls[mid] >= x) {
			r = mid - 1;
			index = mid;
		}
		else {
			l = mid + 1;
		}
	}
	return index + 1;
}
void solve()
{
	int n, m; cin >> n >> m;
	rep(i, 1, n) {
		int x, c; cin >> x >> c;
		add_op.push_back({ x,c });
		alls.push_back(x);
	}

	rep(i, 1, m) {
		int l, r; cin >> l >> r;
		q_op.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 it : add_op) {
		int x = find(it.first);
		a[x] += it.second;
	}

	for (int i = 1; i <= alls.size(); i++) {
		pre[i] = pre[i - 1] + a[i];
	}

	for (auto it : q_op) {
		int l = find(it.first);
		int r = find(it.second);
		cout << pre[r] - pre[l - 1] << endl;
	}

}

y总模板

vector<PII> add_op;
vector<PII> q_op;
vector<int> alls;
int pre[N],a[N];

void solve()
{
	int n, m; cin >> n >> m;
	rep(i, 1, n) {
		int x, c; cin >> x >> c;
		add_op.push_back({ x,c });
		alls.push_back(x);
	}

	rep(i, 1, m) {
		int l, r; cin >> l >> r;
		q_op.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());
	
	unordered_map<int, int> mp;
	int j = 1;
	for (auto it : alls) {
		mp[it] = j++;
	}

	for (auto it : add_op) {
		int index = mp[it.first];
		int val = it.second;
		a[index] += val;
	}

	for (int i = 1; i <= alls.size(); i++) {
		pre[i] = pre[i - 1] + a[i];
	}

	for (auto it : q_op) {
		int l = mp[it.first];
		int r = mp[it.second];
		cout << pre[r] - pre[l - 1] << endl;
	}

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值