题目链接:http://poj.org/problem?id=1733
用sum数组表示序列的前缀和
1. s[l~r]有偶数个1 -> sum[l-r]和sum[r]奇偶性相同
2. s[l~r]有奇数个1 -> sum[l-r]和sum[r]奇偶性不同
有3种传递关系
1. x1与x2奇偶性相同,x2与x3奇偶性相同,则x1与x3奇偶性相同
2. x1与x2奇偶性相同,x2与x3奇偶性不同,则x1与x3奇偶性不同
3. x1与x2奇偶性不同,x2与x3奇偶性不同,则x1与x3奇偶性相同
由于序列长度较大,需要用离散化
struct
{
int l, r, ans;
} query[10010];
int a[maxn],sett[maxn],val[maxn],n,m,t;
void read_discrete() // 读入、离散化
{
cin >> n >> m;
for (int i = 1; i <= m; i++)
{
char str[5];
scanf("%d%d%s", &query[i].l, &query[i].r, str);
if(str[0] == 'o')
query[i].ans = 1;
else
query[i].ans = 0;
a[++t] = query[i].l - 1;
a[++t] = query[i].r;
}
sort(a + 1, a + t + 1);
n = unique(a + 1, a + t + 1) - a - 1;
}
然后“边带权”和“扩展域”两种并查集都可以写
边带权
路径压缩:对x到树根路径上的所有边权做异或操作,即可得到x与树根的奇偶性,边权为0,代表相同,为1,不同
#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
const int maxn = 20010;
struct
{
int l, r, ans;
} query[10010];
int a[maxn],sett[maxn],val[maxn],n,m,t;
void read_discrete() // 读入、离散化
{
cin >> n >> m;
for (int i = 1; i <= m; i++)
{
char str[5];
scanf("%d%d%s", &query[i].l, &query[i].r, str);
if(str[0] == 'o')
query[i].ans = 1;
else
query[i].ans = 0;
a[++t] = query[i].l - 1;
a[++t] = query[i].r;
}
sort(a + 1, a + t + 1);
n = unique(a + 1, a + t + 1) - a - 1;
}
int findSet(int x)
{
if(x==sett[x])
return x;
int y = findSet(sett[x]);
val[x] ^= val[sett[x]];
return sett[x] = y;
}
int main()
{
read_discrete();
int flag = 0;
for (int i = 1; i <= n; i++)
sett[i] = i;
for(int i = 1;i<=m;i++)
{
if(flag)
continue;
// 求出l-1和r离散化之后的值
int x = lower_bound(a + 1, a + n + 1, query[i].l - 1) - a;
int y = lower_bound(a + 1, a + n + 1, query[i].r) - a;
int x1 = findSet(x);
int y1 = findSet(y);
if(x1==y1)
{
if((val[x]^val[y]) != query[i].ans)
{
printf("%d\n",i-1);
flag = 1;
}
}
else// 不在同一集合,合并
{
sett[x1] =y1;
val[x1]= val[x] ^ val[y] ^ query[i].ans;
}
}
if(!flag)
cout << m << endl;
return 0;
}
扩展域
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
struct { int l, r, ans; } query[10010];
int a[20010], sett[40010], n, m, t;
void read_discrete() { // 读入、离散化
cin >> n >> m;
for (int i = 1; i <= m; i++) {
char str[5];
scanf("%d%d%s", &query[i].l, &query[i].r, str);
query[i].ans = (str[0] == 'o' ? 1 : 0);
a[++t] = query[i].l - 1;
a[++t] = query[i].r;
}
sort(a + 1, a + t + 1);
n = unique(a + 1, a + t + 1) - a - 1;
}
int findSet(int x) {
if (x == sett[x]) return x;
return sett[x] = findSet(sett[x]);
}
int main() {
read_discrete();
for (int i = 1; i <= 2 * n; i++) sett[i] = i;
for (int i = 1; i <= m; i++) {
// 求出l-1和r离散化之后的值
int x = lower_bound(a + 1, a + n + 1, query[i].l - 1) - a;
int y = lower_bound(a + 1, a + n + 1, query[i].r) - a;
int x_odd = x, x_even = x + n;
int y_odd = y, y_even = y + n;
if (query[i].ans == 0) { // 奇偶性相同
if (findSet(x_odd) == findSet(y_even)) { // 矛盾
cout << i - 1 << endl;
return 0;
}
sett[findSet(x_odd)] = findSet(y_odd); // 合并
sett[findSet(x_even)] = findSet(y_even);
}
else { // 奇偶性不同
if (findSet(x_odd) == findSet(y_odd)) { // 矛盾
cout << i - 1 << endl;
return 0;
}
sett[findSet(x_odd)] = findSet(y_even); // 合并
sett[findSet(x_even)] = findSet(y_odd);
}
}
cout << m << endl; // 没有矛盾
}