题意:有n个结点,给出了q个操作,操作是a b string表示结点a到结点b的和是奇数或偶数,输出x(前x个操作都是正确的)。
题解:带权并查集经典题,因为结点可能有10,000,000,000个,所以需要离散化,不用的点就不考虑了。因为要a加到b,如果a==b无法找到各自的根节点并判断是否要合并,所以其实是mp[a - 1]到mp[b]并入集合。另外需要注意结点是有顺序的,父亲结点要大于等于子节点,这样判断才不会出错,所以合并时要考虑两个根结点的大小有不同关系式。
#include <stdio.h>
#include <map>
using namespace std;
const int N = 10005;
int pa[N], n, q, cnt, rel[N], l[N], r[N];
char str[N][10];
map<int, int> mp;
int get_parent(int x) {
if (pa[x] != x) {
int px = get_parent(pa[x]);
rel[x] = (rel[x] + rel[pa[x]]) % 2;
pa[x] = px;
}
return pa[x];
}
int main() {
while (scanf("%d", &n) == 1) {
scanf("%d", &q);
mp.clear();
cnt = 1;
for (int i = 1; i <= q; i++) {
scanf("%d%d%s", &l[i], &r[i], str[i]);
if (!mp[l[i] - 1])
mp[l[i] - 1] = cnt++;
if (!mp[r[i]])
mp[r[i]] = cnt++;
}
for (int i = 0; i <= cnt; i++) {
pa[i] = i;
rel[i] = 0;
}
int res = -1;
for (int i = 1; i <= q; i++) {
int flag = str[i][0] == ‘e‘ ? 0 : 1;
int px = get_parent(mp[l[i] - 1]);
int py = get_parent(mp[r[i]]);
if (px != py) {
if (px < py) {
pa[px] = py;
rel[px] = (flag + rel[mp[r[i]]] - rel[mp[l[i] - 1]] + 2) % 2;
}
else {
pa[py] = px;
rel[py] = (rel[mp[l[i] - 1]] - flag - rel[mp[r[i]]] + 4) % 2;
}
}
else {
if ((rel[mp[l[i] - 1]] - rel[mp[r[i]]] + 2) % 2 != flag) {
res = i - 1;
break;
}
}
}
if (res == -1)
res = q;
printf("%d\n", res);
}
return 0;
}
时间: 2024-12-26 19:14:23