P2024
题目大意:给出x是y的同类,x吃y两种关系,求出他们的关系假话总数
思路:维护两个元素的关系较复杂,需要一个元素维护3个部分
A:该元素与它的同类
B:该元素与它的猎物
C:该元素与它的天敌
判断一句话是否为假:
1.xy是同类:是否有吃与被吃,天敌与是天敌的关系
即是和
添加关系:一对一添加
2.x吃y:是否有为同类,y吃x(y是x的天敌)的关系
添加关系:
y的同类作为x的猎物
y的猎物作为x的天敌
y的天敌作为x的同类
#include<bits/stdc++.h>
using namespace std;
const int N = 2e6 + 10;
int n,m,ans,fa[N];
inline int find(int x){
if(fa[x]!=x) return fa[x]=find(fa[x]);
else return x;
}
inline void update(int x,int y){
if(find(x)!=find(y))
fa[find(x)]=find(y);
}
inline int read(){
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){
if(ch=='-') f=-1;
ch=getchar();
}while(ch>='0'&&ch<='9'){
x=x*10+ch-48;ch=getchar();
}return x*f;
}
int main(){
//x是同类 x+n是猎物 x+2*n是天敌
n=read();m=read();
for(int i=1;i<=3*n;i++) fa[i]=i;
for(int i=1,lx,x,y;i<=m;i++){
lx=read();x=read();y=read();
if(x>n||y>n||(lx==2&&x==y)){
ans++;
continue;
}
if(lx==1){
if(find(x+n)==find(y)||find(x+2*n)==find(y)){
ans++;
continue;
}
update(x,y);update(x+n,y+n);update(x+2*n,y+2*n);
}else{
//x吃y
if(find(x)==find(y)||find(x+2*n)==find(y)){
ans++;
continue;
}
update(x,y+2*n);update(x+n,y);update(x+2*n,y+n);
}
}
cout<<ans;
return 0;
}
P9869
题目大意:n种元素间有相等,相反的关系,元素可以被复制为T,F,求一种方案使得未知赋值U数量最少
思路:分类并查集。
考虑两个类型
A:与它相等的元素
B:与它不等的元素
性质:如果元素i同时出现在A与B中,只能是U,即是有
记表示元素i相关的元素编号,初始值
1.直接赋值
被赋值为
2.当与元素i是相等关系时:相关元素与当前元素相等,他们的相等集和不等集合并
当与元素i是不等关系时:相关元素与当前元素不相等,他们当相等集与不等集交叉合并
if(val[i]>0){ //相等关系
merge(val[i],i);merge(val[i]+n,i+n);
}if(val[i]<0){ //不等关系
merge(-val[i],i+n);merge(-val[i]+n,i);
}
3.查询
根据性质:
bool chk(int x,int y){
return find(x)==find(y);
}
int ans=0;
rep(i,1,n)
if(chk(i,i+n))
ans++;
cout<<ans<<endl;