NKOJ 3924 parity
NKOJ 3924 parity
思路:带权并查集
实现方法
- 并查集每个点的点权表示其奇偶性,奇偶性有很多种表示方法。一种是在计算新的值的时候直接加起来 \(\bmod 2\),另一种用了 \(\operatorname{xor}\) 的性质,当 \(0 \operatorname{xor} 1\) \(x\) 次时,
\[0 \operatorname{xor} 1=\begin{cases}
0 & x \bmod 2=0\\
1 & x \bmod 2=1
\end{cases}
\]
这把与奇数和偶数相加的三种情况全部表达出来了。
- 将本题中的数组建模为并查集时,要注意两个区间如果连续,其判定标准是有一个点相同,实际上的区间一般不会有重合的点的,所以我们人为地将区间左边界 \(-1\) 后再用并查集处理。
代码
#include<cstdio>
#include<unordered_map>
#include<algorithm>
#include<string>
#include<iostream>
#define int long long
using namespace std;
int n,m,flag=0,cnt=0;
int f[2000005];
int arr[2000005];
int val[2000005];
unordered_map<int,int> mp;
int getf(int x){
if(f[x]!=x){
int t=f[x];
f[x]=getf(f[x]);
val[x]^=val[t];
}
return f[x];
}
void merge(int x,int y,int oe){
int fx=getf(x);
int fy=getf(y);
if(fx!=fy){
f[fx]=fy;
val[fx]=val[x]^val[y]^oe;
}
else if(val[x]^val[y]!=oe) flag=1;
}
signed main(){
scanf("%lld%lld",&n,&m);
for(int i=1;i<=2000000;i++) f[i]=i;
for(int i=1;i<=m;i++){
int x,y;
scanf("%lld%lld",&x,&y);
if(x>y) swap(x,y);
string s;
cin>>s;
if(mp[x-1]==0) mp[x-1]=++cnt;
if(mp[y]==0) mp[y]=++cnt;
merge(mp[x-1],mp[y],s=="odd");
if(flag) printf("%lld",i-1),exit(0);
}
printf("%lld",m);
return 0;
}
或
#include<cstdio>
#include<unordered_map>
#include<algorithm>
#include<string>
#include<iostream>
using namespace std;
int n,m,flag=0,cnt=0;
int f[2000005];
int arr[2000005];
int val[2000005];
unordered_map<int,int> mp;
int getf(int x){
if(f[x]!=x){
int t=f[x];
f[x]=getf(f[x]);
val[x]+=val[t];
val[x]%=2;
}
return f[x];
}
void merge(int x,int y,int oe){
int fx=getf(x);
int fy=getf(y);
if(fx!=fy){
f[fx]=fy;
val[fx]=(val[y]+val[x]+oe)%2;
}
else{
if((val[x]+val[y])%2!=oe) flag=1;
}
}
int main(){
scanf("%d%d",&n,&m);
for(int i=1;i<=2000000;i++) f[i]=i;
for(int i=1;i<=m;i++){
int x,y;
scanf("%d%d",&x,&y);
string s;
cin>>s;
if(mp[x-1]==0) mp[x-1]=++cnt;
if(mp[y]==0) mp[y]=++cnt;
merge(mp[x-1],mp[y],s=="odd"?1:0);
if(flag) printf("%d",i-1),exit(0);
}
printf("%d",m);
return 0;
}
区别在于一个用的 \(\operatorname{xor}\) 一个用的 \(\bmod 2\) 。
注意事项
- 本题中的数据量较大,应当先使用
map
进行离散化再处理,要注意上文提到的左区间 -1 的操作应当在离散化之前就减掉,否则有可能出现哈希冲突。 - 在初始化数组时,由于不知道最大值是多少,需要从头到尾将数组整个初始化,在初始化时要注意数组是从 \(0\sim n-1\) 的,不要给自己整
RE
了。