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\)

注意事项

  1. 本题中的数据量较大,应当先使用 map 进行离散化再处理,要注意上文提到的左区间 -1 的操作应当在离散化之前就减掉,否则有可能出现哈希冲突。
  2. 在初始化数组时,由于不知道最大值是多少,需要从头到尾将数组整个初始化,在初始化时要注意数组是从 \(0\sim n-1\) 的,不要给自己整 RE 了。
posted @ 2024-12-14 10:00  hsr_ray  阅读(24)  评论(0)    收藏  举报