Luogu P14521 加减乘除题解
P14521 【MX-S11-T2】加减乘除
大意随便看看就看懂了,然后很容易能注意到对于每一条边的范围可以提前进行预处理,解不等式得出:
- 到达每一个点所要求的\(x\)的取值范围,跑一个\(dfs\)就可以全部处理完了。
然后发现,问题转化成了一个求\(x\)被多少个区间所包含的问题,想到使用差分数组,但是由于数据保证:\(-10^{18} \le x, a_i \le 10^{18}\)
数组显然是无法容纳,或许想到对他进行离散化,但是由于注意到最多只有\(n-1\)个区间,所以只有\((n-1)\times2\)个位置需要进行差分。
也就是说,我们只需要离线询问,对于\(q\)次询问的\(x\)从小到大排序,然后对所有区间的端点进行从小到大排序,在枚举\(x\)的同时进行差分达到类似离散化的效果。
最后进行前缀和便可求出答案。
以下便是差分数组+扫描线的过程,预处理的过程省去了
vector<pair<int, int>> query;
for (int i = 1; i <= q; i++)
{
int x;
cin >> x;
query.push_back({x, i});// 存储询问的数字与编号
}
sort(query.begin(), query.end());
vector<pair<int, int>> event;
for (int i = 0; i < pq.size(); i++)// pq是在预处理中存储区间的数组
{
if (pq[i].first > pq[i].second)
continue;
event.push_back({pq[i].first, 1});
event.push_back({pq[i].second + 1, -1});//构建差分数组所需要的区间前后端点
}
sort(event.begin(), event.end());
vector<int> cnt(Q);
int idx = 0, sum = 0;//idx是event数组的指针
for (auto [x, i] : query)//便利询问
{
while (idx < event.size() && event[idx].first <= x)//当event存储的区间小于x的时候,说明x的答案可以累计通过他的和所求
{
sum += event[idx++].second;//sum用于累计前缀和
}
cnt[i] += sum;//前缀和求出答案
}
关于使用差分数组+前缀和求多个区间中包含某个点 x 的区间个数,是我通过这道题掌握的知识,以下做简单介绍用于复习:
1.基本思想
把每个区间转换成两个事件
- 在区间开始位置\(l\): +1(表示进入了一个新区间)
- 在区间结束的后一位置\(r+1\):-1(表示离开一个区间)
然后进行前缀和就可以计算每个位置被多少个区间覆盖
2.一个比喻
把数轴想象成一条路,有一辆车在区间上行驶
- 当\(diff[l] += 1\):车在\(l\)位置有1人上车
- 当\(diff[r + 1]-=1\):车在\(r+1\)位置有1人下车
- 前缀和:计算车上在\(x\)点的总人数
这样,车在位置\(x\)位置的人数便是覆盖该位置的区间个数,实现了O(1) 添加区间,O(n) 预处理,O(1) 查询。

浙公网安备 33010602011771号