马赛克
题面
题解
这道题想了很久如何快速求出一个点最右边或者最左边的不相容点,但是没有什么思路。
我们将题目中给定的有序对抽象为 \((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;
}