25 LCA模拟赛3T1 ROI 2012马赛克 题解

马赛克

题面

题解

这道题想了很久如何快速求出一个点最右边或者最左边的不相容点,但是没有什么思路。

我们将题目中给定的有序对抽象为 \((a,b)\)

最后 xpigeon 带神给出了一个结论,就是一段序列中只要出现了两个互不相同的 \(a\) ,并且出现了两个互不相同的 \(b\),那么就一定会不相容。

我们来证明一下:

对于两个数对的情况,显然不相容。

对于三个数对的情况,假设前两个相容,那么一定是形如 \((x,y), (x, *)\) 或者 \((x, y), (*, y)\),我们讨论第一个情况,第二种情况同理。

假设前两个完全相同,那么和两个数对的情况相同,所以我们只讨论前两个不同的情况。

前两个为 \((x, y), (x, q)\) 为了出现两个互不相同的 \(a\),第三个数对一定为 \((p, *)\) 其中 \(*\) 可能为 \(y\)\(q\) 或其他。

那么不管 \(*\) 取哪种情况,都会和前两个中的某一个不相容。

对于大于等于三个数对的情况,我们同样可以按照三个数对的情况推得。

有了这样一个结论,我们只需找到对于每个数对右边的第一个 \(a\) 与其不同的数对,以及第一个 \(b\) 与其不同的数对。

然后看这两个数对的位置是否都包含在我们的区间范围内即可。

时间复杂度 \(O(n)\)

code

#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdio>
#include <vector>
#include <map>
#include <set>

using namespace std;

namespace michaele {

    const int N = 1e5 + 10;

    int n, m;
    pair <int, int> a[N];
    int ne1[N], ne2[N];

    void solve () {
        cin >> n;
        for (int i = 1; i <= n; i ++) {
            cin >> a[i].first >> a[i].second;
        }
        for (int i = n; i >= 1; i --) {
            if (a[i + 1].first != a[i].first) ne1[i] = i + 1;
            else ne1[i] = ne1[i + 1];
            if (a[i + 1].second != a[i].second) ne2[i] = i + 1;
            else ne2[i] = ne2[i + 1];
        }
        cin >> m;
        for (int i = 1; i <= m; i ++) {
            int l, r, x, y;
            cin >> l >> r;
            x = ne1[l], y = ne2[l];
            if (x > r || y > r) {
                cout << "0 0" << endl;
            } else if (a[l].second != a[x].second) {
                cout << l << ' ' << x << endl;
            } else if (a[l].first != a[y].first) {
                cout << l << ' ' << y << endl;
            } else {
                cout << x << ' ' << y << endl;
            }
        }
    }

}


int main () {

    michaele :: solve ();

    return 0;
}
posted @ 2025-10-16 15:03  michaele  阅读(4)  评论(0)    收藏  举报