【题目链接】
http://poj.org/problem?id=1733
题目意思
给个01组成的的字符串,如果根据1的个数分奇偶性,现在给你每个区间段的奇偶性,问你是否冲突,输出到第几个不冲突。
解题思路
并查集的一种模型,冲突的条件是当1个完全重合区间段出现两次不一样的结果时才冲突。如:【1,8】为偶性,【1,4】为奇性,【5,8】为偶性,这时就发生冲突。所以用并查集记录每个点已知的区间的奇偶性(可理解为某点到现在为止所知最远的区间左点(右点)),当两点已知的区间相同时就判断是否冲突。需要注意的是查询【l,r】区间时应查询l-1和r的集合。(如上例子查询【5,8】是应查询4和8)。另外就是在合并时候注意权值的变化。两集合合并时注定要把其中一个的pre【x】更新。而保留的应该是最左或最右,这题又计较特殊随便合并都没事是。(不懂可以参考poj3038自己画画)
代码部分
#include <iostream>
#include <algorithm>
#include <stdio.h>
#include <string.h>
#include <queue>
#include <string>
#include <map>
using namespace std;
#define LL long long
#define inf 0x3f3f3f3
const int N = 1e4+5;
struct node
{
int x,y;
char str[10];
}q[N];
int n,m,cnt;
int a[N]; ///离散化存储
int pre[N];
int val[N]; ///保存区间 i到pre[i]的奇偶性
int fin(int x) ///查询
{
int k = pre[x];
if (pre[x] != x)
{
pre[x] = fin(pre[x]);
val[x] = (val[x]+val[k])%2; ///加上对应区间,判断是否改变奇偶
}
return pre[x];
}
int main()
{
while (scanf("%d",&n)!=EOF)
{
scanf("%d",&m);
for (int i = 0; i < m;i++)
{
scanf("%d %d %s",&q[i].x,&q[i].y,q[i].str);
q[i].x--;
a[cnt++] = q[i].x;
a[cnt++] = q[i].y;
}
sort(a,a+cnt);
cnt = unique(a,a+cnt)-a; ///去重
for (int i = 0; i < cnt; i++)
{
pre[i] = i;
val[i] = 0;
}
int ans = 0;
for (int i = 0; i < m; i++)
{
int x = lower_bound(a,a+cnt,q[i].x)-a; ///在a数组中找到第一个大于等于x的值
int y = lower_bound(a,a+cnt,q[i].y)-a;
int fx = fin(x);
int fy = fin(y);
if (fx == fy) ///已经出现过这段区间
{
if (val[x] == val[y] && q[i].str[0] == 'o')
break;
if (val[x] != val[y] && q[i].str[0] == 'e')
break;
ans++;
}
else ///否则合并集合同时判断第三段的奇偶性
{
if (q[i].str[0] == 'o')
{
pre[fx] = fy;
val[fx] = (val[x]+val[y]+1)%2;
}
else
{
pre[fx] = fy;
val[fx] = (val[x]+val[y])%2;
}
ans++;
}
}
printf("%d\n",ans);
}
return 0;
}