算法笔记
带权并查集大神详解:https://agatelee.cn/2017/05/%E5%B8%A6%E6%9D%83%E5%B9%B6%E6%9F%A5%E9%9B%86/
贴几道题的代码:
#include<iostream> #include<cstdio> using namespace std; const int N=1e5+5; int fa[N],rnk[N]; void Init(int n) { for(int i=0;i<=n;i++) { fa[i]=i; rnk[i]=0; } } int Find(int x) { if(x==fa[x])return x; int temp=fa[x]; fa[x]=Find(fa[x]); rnk[x]=(rnk[x]+rnk[temp])%3; return fa[x]; } void Merge(int r,int x,int y) { int rx=Find(x); int ry=Find(y); if(rx==ry)return ; fa[rx]=ry; rnk[rx]=(r+rnk[y]-rnk[x]+3)%3; } int main() { int n,k; cin>>n>>k; Init(n); int ans=0; while(k--) { int a,b,c; scanf("%d%d%d",&a,&b,&c); a--; if(b>n||c>n) { ans++; continue; } if(a==1&&b==c) { ans++; continue; } int rb=Find(b); int rc=Find(c); if(rb!=rc)Merge(a,b,c); else { if((rnk[b]-rnk[c]+3)%3!=a)ans++; } } cout<<ans<<endl; return 0; }
这道题目不知道为啥用ios::sync_with_stdio(false)和cin是TLE,用ios:cync_with_stdi(false)和scanf()是WA。
详见知乎:用ios::sync_with_stdio(false)有什么坏处
#include<iostream> #include<cstdio> using namespace std; const int N=1e5+5; int fa[N],rnk[N]; void Init(int n) { for(int i=0;i<=n;i++) { fa[i]=i; rnk[i]=0; } } int Find(int x) { if(x==fa[x])return x; int temp=fa[x]; fa[x]=Find(fa[x]); rnk[x]=rnk[x]+rnk[temp]; return fa[x]; } void Merge(int s,int x,int y) { int rx=Find(x); int ry=Find(y); if(rx==ry)return ; fa[rx]=ry; rnk[rx]=s+rnk[y]-rnk[x]; } int main() { int n,m,q; cin>>n>>m>>q; Init(n); while(m--) { int a,b,c; scanf("%d%d%d",&a,&b,&c); Merge(c,a,b); } while(q--) { int a,b; scanf("%d%d",&a,&b); int ra=Find(a); int rb=Find(b); if(ra!=rb)printf("-1 "); else printf("%d ",rnk[a]-rnk[b]); } return 0; }
③Codeforces 766D - Mahmoud and a Dictionary
#include<bits/stdc++.h> using namespace std; const int N=1e5+5; int fa[N],rnk[N]; map<string,int>ma; void Init(int n) { for(int i=0;i<=n;i++) { fa[i]=i; rnk[i]=0; } } int Find(int x) { if(x==fa[x])return x; int temp=fa[x]; fa[x]=Find(fa[x]); rnk[x]=(rnk[x]+rnk[temp])%2; return fa[x]; } void Merge(int r,int x,int y) { int rx=Find(x); int ry=Find(y); if(rx==ry)return; fa[rx]=ry; rnk[rx]=(r+rnk[y]-rnk[x]+2)%2; } int main() { ios::sync_with_stdio(false); cin.tie(0); int n,m,q; cin>>n>>m>>q; Init(n); int a; string s1,s2; for(int i=0;i<n;i++) { cin>>s1; ma[s1]=i; } while(m--) { cin>>a>>s1>>s2; a--; int rs1=Find(ma[s1]); int rs2=Find(ma[s2]); if(rs1!=rs2) { Merge(a,ma[s1],ma[s2]); cout<<"YES"<<endl; } else { if((rnk[ma[s1]]-rnk[ma[s2]]+2)%2!=a) cout<<"NO"<<endl; else cout<<"YES"<<endl; } } while(q--) { cin>>s1>>s2; int rs1=Find(ma[s1]); int rs2=Find(ma[s2]); if(rs1!=rs2)cout<<3<<endl; else cout<<((rnk[ma[s1]]-rnk[ma[s2]]+2)%2+1)<<endl; } return 0; }
ps:
可以用向量的方法考虑rnk之间的变化;
rnk[i] 表示的是i与i直接父亲节点的关系,在没有路径压缩之前不是i与根节点的关系,在路径压缩之后直接父亲就是根节点,此时才是与根节点的关系。所以只需要在直接父亲改变的情况下才需要改变rnk[i]的值。这点也是我最近才考虑清楚的,以前太菜了,没想清楚就以为自己懂了。