题意:
有一串长为的01串,给出个问题,每个问题会给出一个区间范围和该范围内的个数的奇偶性,但是每当提出一个新问题都有可能会和已知问题产生冲突。问产生冲突的问题的最小序号。
分析:
乍一看并不像并查集能够处理的问题,但是范围的左右端点到的奇偶性是可以被统计的,所以区间内为如果偶数,则可以说明的奇偶性一样,奇数则相反。这就类似于扩展域并查集,将区间的两个端点分为两个点,分别表示这两种性质,如果这两种性质有关联(同奇偶或不同奇偶),则合并这两个点,最终检验的时候只需判断点是否属于同一个集合即可。
另外值得注意的一点是,该题的范围很大,需要做离散化处理,并且并查集的初始化需要在离散化后才可以进行,否则会出现一系列越界的情况。
代码:
#include <bits/stdc++.h> #define int long long using namespace std; constexpr int mod = 1e9 +7; //constexpr int mod2 = 998244353; constexpr int MAXNe5 = 2e5 +7; constexpr int MAXNe6 = 1e6 + 7; typedef long long ll; #pragma region inline long long read() { char c = getchar();long long flag = 1, ans = 0; while(c < '0' || c > '9'){if(c == '-') flag = -1; c = getchar();} while(c >= '0' && c <= '9'){ans = ans * 10 + c - '0'; c = getchar();} return (ans * flag); } #pragma endregion // C'est la vie struct { int a, b, tag; }input[MAXNe5]; int fa[MAXNe5], num[MAXNe5], len = 0, k = 0, n = 0; int find(int x) { return (fa[x] == x) ? x : fa[x] = find(fa[x]); } void merge(int x, int y) { fa[find(x)] = find(y); } void init() { cin >> len >> k; int tmp = 0; for(int i = 1; i <= k; ++ i) { string opt; cin >> input[i].a >> input[i].b >> opt; input[i].tag = (opt == "even") ? 0 : 1; num[++ tmp] = input[i].a - 1; num[++ tmp] = input[i].b; } sort(num + 1, num + tmp + 1); n = unique(num + 1,num + tmp + 1) - num - 1; for(int i = 1; i <= 2 * n + 1; ++ i) fa[i] = i; } signed main() { ios::sync_with_stdio(false); init(); for(int i = 1; i <= k; ++ i) { int x = lower_bound(num + 1, num + n + 1, input[i].a - 1) - num, y = lower_bound(num + 1, num + n + 1, input[i].b) - num; if(input[i].tag) { if(find(x) == find(y)) { cout << i - 1 << endl; return 0; } merge(x, y + n); merge(x + n, y); } else { if(find(x) == find(y + n)) { cout << i - 1 << endl; return 0; } merge(x, y); merge(x + n, y + n); } } cout << k << endl; #ifndef ONLINE_JUDGE system("pause"); #endif }