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) 查询

posted @ 2025-11-18 19:34  tree_one  阅读(0)  评论(0)    收藏  举报