poj 1733 并查集+hashmap

时间:2025-01-17 23:37:38

题意:题目:有一个长度 已知的01串,给出多个条件,[l,r]这个区间中1的个数是奇数还是偶数,问前几个是正确的,没有矛盾

链接:点我

解题思路:hash离散化+并查集

首先我们不考虑离散化:s[x]表示(root[x],x]区间1的个数的奇偶性,0-偶数,1-奇数

每个输入区间[a,b],首先判断a-1与b的根节点是否相同

a)如果相同表示(a-1,b]之间1的个数奇偶性已知s((a-1,b])=s[a-1]^s[b],此时只需简单判断即可

b)如果不同,我们需要合并两个子树,我们将root较大的子树(例root[a])合并到root较小的子树(例root[b]),且此时s[root[a]]=s[a]^s[b]^s((a-1,b])

在路径压缩的过程中s[i]=s[i]^s[root[i]],s[root[i]]为(root[root[i]], root[i]]区间内1个数的奇偶性,例(a, b]区间1的个数为偶数,(b, c]区间1的个数为奇数,(a, c]之间1的个数显然为0^1=1奇数

 /*
POJ 1733
HASH+并查集实现
*/
#include <stdio.h>
#include <algorithm>
#include <iostream>
#include <string.h>
using namespace std; const int HASH=;
const int MAXN=; struct HASHMAP
{
int head[HASH];
int next[MAXN];
int size;
int state[MAXN];
void init()
{
size=;
memset(head,-,sizeof(head));
}
int push(int st)
{
int i,h=st%HASH;
for(i=head[h];i!=-;i=next[i])
if(state[i]==st)
return i;
state[size]=st;
next[size]=head[h];
head[h]=size++;
return size-;
}
}hm;
int F[MAXN];
int val[MAXN];
int find(int x)
{
if(F[x]==-)return x;
int tmp=find(F[x]);
val[x]^=val[F[x]];
return F[x]=tmp;
} int main()
{
int n,m;
int u,v;
char str[];
while(scanf("%d%d",&n,&m)==)
{
hm.init();
memset(F,-,sizeof(F));
memset(val,,sizeof(val));
int ans=m;
for(int i=;i<m;i++)
{
scanf("%d%d%s",&u,&v,&str);
if(u>v)swap(u,v);
if(ans<m)continue; u=hm.push(u-);
v=hm.push(v);
//printf("%d %d\n",u,v); int tmp;
if(str[]=='e')tmp=;
else tmp=;
int t1=find(u);
int t2=find(v); if(t1==t2)
{
if(val[u]^val[v]!=tmp)ans=i;
}
else
{
F[t2]=t1;
val[t2]=tmp^val[u]^val[v];
} }
printf("%d\n",ans);
}
return ;
}