题单链接
https://vjudge.net/article/752
1. POJ-2236 Wireless Network
//https://vjudge.net/problem/POJ-2236
#include <cstdio>
#define N 1005
int f[N];
bool broken[N];
int n,d,D,p,q;
char Q[3];
int X[N],Y[N];
int Fa (int x)
{
return f[x]==x ? x : f[x]=Fa(f[x]);
}
inline int fail(int u,int v)
{
return (X[u]-X[v])*(X[u]-X[v])+(Y[u]-Y[v])*(Y[u]-Y[v])>D;
}
int main()
{
scanf("%d%d",&n,&d);
D=d*d;
for (int i=1; i<=n; i++) {
broken[i]=1;
f[i]=i;
scanf("%d%d",&X[i],&Y[i]);
}
while (scanf("%s",Q)!=EOF) {
if (Q[0]=='O') {
scanf("%d",&p);
for (int i=1; i<=n; i++) {
if (i!=p && !broken[i] && !fail(p,i)) {
f[Fa(i)]=Fa(p);
}
}
broken[p]=0;
}
else {
scanf("%d%d",&p,&q);
puts(Fa(p)==Fa(q) ? "SUCCESS" : "FAIL");
}
}
return 0;
}
2. POJ-1611 The Suspects
//https://vjudge.net/problem/POJ-1611
#include <cstdio>
#define N 30005
int f[N],vis[N];
int Fa(int x) {return f[x]==x ? x : f[x]=Fa(f[x]);}
int n,m,ans,k,u,v,fu,fv,tmp;
int main()
{
while (1) {
scanf("%d%d",&n,&m);
if (n==0 && m==0) {
break;
}
for (int i=0; i<n; i++) {
f[i]=i;
vis[i]=0;
}
while (m--) {
scanf("%d",&k);
if (k<=0) {
continue;
}
scanf("%d",&v);
fv=Fa(v);
while (--k) {
u=v;
fu=fv;
scanf("%d",&v);
fv=Fa(v);
if (fu!=fv) {
ans--;
f[fu]=fv;
}
}
}
tmp=Fa(0);
ans=0;
for (int i=0; i<n; i++)
ans+=(Fa(i)==tmp);
printf("%d\n",ans);
}
return 0;
}
3. HDU-1213 How Many Tables
//https://vjudge.net/problem/HDU-1213
#include <cstdio>
#include <iostream>
using namespace std;
short int f[1000],T,n,m,u,v,fu,fv;
inline int Fa(int x) {
return f[x]==x ? x : f[x]=Fa(f[x]);
}
int main()
{
cin >>T;
while (T--) {
cin >>n >>m;
for (int i=0; i<n; i++) {
f[i]=i;
}
while (m--) {
cin >>u >>v;
u--,v--;
fu=Fa(u);
fv=Fa(v);
if (fu<fv) {
swap(fu,fv);
}
if (fu!=fv) {
n--;
f[fu]=fv;
}
}
cout <<n <<endl;
}
return 0;
}
4. HDU-3038 How Many Answers Are Wrong
带权并查集
写了篇博客
https://blog.csdn.net/jackypigpig/article/details/113348863
//https://vjudge.net/problem/HDU-3038
#include <cstdio>
//设当前节点为 x
//f: 指向的父节点 (f>x)
//s: 区间 (x,f] 的和 (左开右闭)
int f[200005],s[200005];
int n,m,a,b,fa,fb,z,ans;
int Fa(int x)
{
if (f[x]!=x) {
int tmp=f[x];
f[x]=Fa(tmp); //先压缩好父节点的路径,维护好其 s[] 值后才能计算当前节点的 s[] 值
s[x]+=s[tmp];
}
return f[x];
}
void init() {
ans=0;
for (int i=0; i<=n; i++) { //注意从 0 开始,因为开区间,会用到 0
f[i]=i;
s[i]=0;
}
}
int main()
{
while (scanf("%d%d",&n,&m)!=EOF) {
init();
while (m--) {
scanf("%d%d%d",&a,&b,&z);
a--;
fa=Fa(a);
fb=Fa(b);
if (fa==fb) {
ans+=(s[a]-s[b]!=z); //判断是否失败
}
else {
f[fa]=fb;
s[fa]=z+s[b]-s[a]; //向量加减得到
}
}
printf("%d\n",ans);
}
return 0;
}
5. POJ-1182 食物链
同样,给边附一个取3模意义下的权值,来个带权值并查集即可。
//https://vjudge.net/problem/POJ-1182
#include <cstdio>
#define N 50005
int f[N]; //并查集
int g[N]; //与父亲的关系 (0:x=f 1:x>f 2:x<f)
int ans,n,k,D,a,b,fa,fb,p;
int Fa(int x)
{
if (f[x]!=x) {
int tmp=f[x];
f[x]=Fa(tmp);
g[x]=(g[x]+g[tmp])%3;
}
return f[x];
}
void init()
{
ans=0;
for (int i=1; i<=n; i++) {
f[i]=i;
g[i]=0;
}
}
int main()
{
scanf("%d%d",&n,&k);
init();
while (k--) {
scanf("%d%d%d",&D,&a,&b);
if (a>n || b>n) {
ans++;
continue;
}
p=(D==2); //a->b = p
fa=Fa(a);
fb=Fa(b);
if (fa==fb) {
ans+=((g[a]-g[b]+3)%3!=p);
}
else {
f[fa]=fb;
g[fa]=(p+g[b]-g[a]+3)%3;
}
}
printf("%d\n",ans);
return 0;
}
6.
7. POJ-1456 Supermarket
按利润从大到小一次选,能选就选,记下时间,利用并查集压缩路径。
#include <cstdio>
#include <algorithm>
#define I c[i]
using namespace std;
long long ans,n,t,f[10002],p[10002],d[10002],c[10002];
bool cmp(long long x, long long y)
{
return p[x]>p[y];
}
long long Fa(long long &x)
{
return f[x]==x ? x : f[x]=Fa(f[x]);
}
int main()
{
while (scanf("%lld",&n)==1)
{
ans=0;
for (long long i=0; i<=10000; i++)
f[i]=i;
for (long long i=1; i<=n; i++)
{
scanf("%lld%lld",&p[i],&d[i]);
c[i]=i;
}
sort(c+1,c+n+1,cmp);
for (long long i=1; i<=n; i++)
{
t=Fa(d[I]);
if (t>0)
{
ans+=p[I];
f[t]=t-1;
}
}
printf("%lld\n",ans);
}
return 0;
}
8. POJ-1733 Parity game
带权并查集
#include <cstdio>
#include <map>
using namespace std;
map<int, int> mp;
int L,Q,cnt,l[5005],r[5005],DD[5005],f[10005],v[10005];
int Fa(int x)
{
if (f[x]==x)
{
return x;
}
int tmp=f[x];
f[x]=Fa(tmp);
v[x]=(v[x]+v[tmp]+2)%2;
return f[x];
}
int main()
{
char s[8];
int fail,a,b,D,fa,fb;
while (scanf("%d",&L)==1)
{
scanf("%d",&Q);
mp.clear();
cnt=0;
fail=Q;
for (int i=1; i<=Q; i++)
{
scanf("%d%d%s",&l[i],&r[i],s);
DD[i]=(s[0]=='o');
l[i]--;
if (!mp[l[i]])
mp[l[i]]=++cnt;
if (!mp[r[i]])
mp[r[i]]=++cnt;
}
for (int i=1; i<=cnt; i++)
{
f[i]=i;
v[i]=0;
}
for (int i=1; i<=Q; i++)
{
a=mp[l[i]];
b=mp[r[i]];
fa=Fa(a);
fb=Fa(b);
D=DD[i];
if (fa==fb)
{
if ((v[a]-v[b]+2)%2!=D)
{
fail=i-1;
break;
}
}
else
{
v[fa]=(D-v[a]+v[b]+2)%2;
f[fa]=fb;
}
}
printf("%d\n",fail);
}
return 0;
}
9. POJ-1984 Navigation Nightmare
带权并查集
#include <cstdio>
#include <iostream>
#include <algorithm>
#define N 40005
using namespace std;
long long n,m,aa[N],bb[N],ll[N];
long long c[10005],cnt,k,q[10005][3];
long long a,b,l,fa,fb;
long long fx[N],fy[N],vx[N],vy[N];
char s,ss[N][2];
bool cmp(int x, int y)
{
return q[x][2]<q[y][2];
}
long long Fa(long long x, long long f[], long long v[])
{
if (f[x]==x)
{
return x;
}
long long tmp=f[x];
f[x]=Fa(tmp,f,v);
v[x]+=v[tmp];
return f[x];
}
void solve(long long A, long long B)
{
long long fxA,fxB,fyA,fyB;
fxA=Fa(A,fx,vx);
fxB=Fa(B,fx,vx);
fyA=Fa(A,fy,vy);
fyB=Fa(B,fy,vy);
if (fxA!=fxB || fyA!=fyB)
{
puts("-1");
return;
}
printf("%lld\n",abs(vx[A]-vx[B])+abs(vy[A]-vy[B]));
}
int main()
{
while (scanf("%lld%lld",&n,&m)==2)
{
for (long long i=1; i<=m; i++)
{
scanf("%lld%lld%lld%s",&aa[i],&bb[i],&ll[i],ss[i]);
if (ss[i][0]=='S' || ss[i][0]=='W')
{
ll[i]=-ll[i];
}
}
scanf("%lld",&k);
for (long long i=1; i<=k; i++)
{
scanf("%lld%lld%lld",&q[i][0],&q[i][1],&q[i][2]);
c[i]=i;
}
sort(c+1,c+k+1,cmp);
// init
for (int i=1; i<=n; i++)
{
fx[i]=fy[i]=i;
vx[i]=vy[i]=0;
}
cnt=1;
for (long long i=1; i<=m; i++)
{
a=aa[i],b=bb[i],l=ll[i],s=ss[i][0];
if (s=='E' || s=='W')
{
fa=Fa(a,fx,vx);
fb=Fa(b,fx,vx);
if (fa!=fb)
{
vx[fa]=l-vx[a]+vx[b];
fx[fa]=fb;
}
fa=Fa(a,fy,vy);
fb=Fa(b,fy,vy);
if (fa!=fb)
{
vy[fa]=vy[b]-vy[a];
fy[fa]=fb;
}
}
else
{
fa=Fa(a,fy,vy);
fb=Fa(b,fy,vy);
if (fa!=fb)
{
vy[fa]=l-vy[a]+vy[b];
fy[fa]=fb;
}
fa=Fa(a,fx,vx);
fb=Fa(b,fx,vx);
if (fa!=fb)
{
vx[fa]=vx[b]-vx[a];
fx[fa]=fb;
}
}
while (cnt<=k && q[cnt][2]==i)
{
solve(q[cnt][0],q[cnt][1]);
cnt++;
}
if (cnt>k)
{
break;
}
}
}
return 0;
}
10. POJ-2492 A Bug’s Life
#include <cstdio>
int f[2005],v[2005];
int Fa(int x)
{
if (f[x]==x)
{
return x;
}
int tmp=f[x];
f[x]=Fa(tmp);
v[x]^=v[tmp];
return f[x];
}
int main()
{
int T,n,m;
scanf("%d",&T);
for (int t=1; t<=T; t++)
{
scanf("%d%d",&n,&m);
for (int i=1; i<=n; i++)
{
f[i]=i;
v[i]=0;
}
int fail=0,a,b,fa,fb;
for (int i=1; i<=m; i++)
{
scanf("%d%d",&a,&b);
if (fail)
{
continue;
}
fa=Fa(a);
fb=Fa(b);
if (fa==fb)
{
if (v[a]^v[b]!=1)
{
fail=1;
}
}
else
{
v[fa]=1^(v[a]^v[b]);
f[fa]=fb;
}
}
printf("Scenario #%d:\n",t);
puts(fail ? "Suspicious bugs found!" : "No suspicious bugs found!");
if (t<T)
puts("");
}
return 0;
}
11. POJ-2912 Rochambeau
枚举裁判,然后每次都重新维护一个并查集直到出现矛盾,根据矛盾次数与每次的矛盾位点给出答案。
#include <cstdio>
#include <cstring>
#define MAXN 505
#define MAXM 2005
int JUDGE;
int n,m;
int f[MAXN],df[MAXN];
struct round {
int u,v,d; //u->v , v-u=d
} rd[MAXM];
void initf()
{
for (int i=0; i<n; i++) {
f[i]=i;
df[i]=0;
}
}
int Fa(int x)
{
if (f[x]==x)
return x;
int fa=Fa(f[x]);
df[x]=(df[x]+df[f[x]]+6)%3;
f[x]=fa;
return fa;
}
void join(int x, int y, int d) //y-x=d
{
int fx=Fa(x);
int fy=Fa(y);
if (fx!=fy) {
f[fy]=fx;
df[fy]=(d+df[x]-df[y]+6)%3;
}
else {
//这个情况在本程序中不应该会发生
}
}
bool check(int &pos)
{
pos=0;
int fu,fv;
for (int i=0; i<m; i++) {
if (rd[i].u!=JUDGE && rd[i].v!=JUDGE) {
fu=Fa(rd[i].u);
fv=Fa(rd[i].v);
if (fu==fv) {
if ((df[rd[i].v]-df[rd[i].u]+6)%3 != rd[i].d) {
pos=i+1;
return false;
}
}
else {
join(rd[i].u,rd[i].v,rd[i].d);
}
}
}
return true;
}
void solve()
{
int ans;
int cnt=0;
int pos=0,tmppos;
for (int i=0; i<n; i++) {
JUDGE=i;
initf(); //初始化并查集
if (check(tmppos)) {
cnt++;
ans=JUDGE;
}
pos=(pos<tmppos) ? tmppos : pos; //记录按顺序最多需要的条数
}
if (cnt==0) {
printf("Impossible\n");
}
else if (cnt==1) {
printf("Player %d can be determined to be the judge after %d lines\n",ans,pos);
}
else {
printf("Can not determine\n");
}
}
int main()
{
char ch;
while (scanf("%d%d",&n,&m)==2) {
for (int i=0; i<m; i++) {
scanf("%d %c %d",&rd[i].u,&ch,&rd[i].v);
rd[i].d= (ch=='=') ? 0 : (ch=='>' ? 2 : 1);
}
solve();
}
return 0;
}
/*
3 3
0 < 1
1 < 2
2 < 0
3 5
0 < 1
0 > 1
1 < 2
1 > 2
0 < 2
4 4
0 < 1
0 > 1
2 < 3
2 > 3
1 0
*/
12. ZOJ-3261 Connections in Galaxy War
反过来,变成插入边,再维护一个并查集,合并的时候考虑一下s值和编号就行了。ZOJ账号用不了了,没法测,不知道代码对不对。
#include <cstdio>
#include <map>
#include <iostream>
#include <stack>
using namespace std;
#define MAXN 10005
#define MAXM 20005
#define MAXQ 50005
int s[MAXN];
int n,m,q;
int f[MAXN];
struct qry {
char opr;
int x,y;
}Q[MAXQ];
int Fa(int x)
{
return f[x]==x ? x : f[x]=Fa(f[x]);
}
void conj(pair<int, int> P)
{
int u=P.first;
int v=P.second;
int fu=Fa(u);
int fv=Fa(v);
if (fu!=fv) {
if (s[fu]<s[fv]) {
f[fu]=fv;
}
else if (s[fu]>s[fv]) {
f[fv]=fu;
}
else {
(fu<fv) ? f[fv]=fu : f[fu]=fv;
}
}
}
int main()
{
while (scanf("%d",&n)==1) {
for (int i=0; i<n; i++) {
scanf("%d",&s[i]);
f[i]=i;
}
scanf("%d",&m);
map<pair<int,int>, int> M;
pair<int, int> E[MAXM];
for (int i=0; i<m; i++) {
scanf("%d%d",&E[i].first,&E[i].second);
if (E[i].first>E[i].second)
swap(E[i].first,E[i].second);
M[E[i]]=1;
}
scanf("%d",&q);
char str[10];
for (int i=0; i<q; i++) {
scanf("%s",str);
if ((Q[i].opr=str[0])=='q') {
scanf("%d",&Q[i].x);
}
else {
scanf("%d%d",&Q[i].x,&Q[i].y);
if (Q[i].x>Q[i].y)
swap(Q[i].x,Q[i].y);
M[make_pair(Q[i].x,Q[i].y)]=0;
}
}
//构造最后状态
for (int i=0; i<m; i++) {
if (M[E[i]]) {
conj(E[i]);
}
}
//倒序处理答案
stack<int> ans;
for (int i=q-1; i>=0; i--) {
if (Q[i].opr=='q') {
int tmp=Fa(Q[i].x);
ans.push(s[tmp]==s[Q[i].x] ? -1 : tmp);
}
else {
conj(make_pair(Q[i].x,Q[i].y));
}
}
//顺序输出
while (!ans.empty()) {
printf("%d\n",ans.top());
ans.pop();
}
}
return 0;
}
/*
3
20 20 20
3
1 2
0 1
0 2
4
query 1
query 2
destroy 1 2
query 2
-1
-1
-1
*/
13. HDU-1272 小希的迷宫
模板题,判断是不是一棵树
#include <cstdio>
#include <cstring>
#define N 100005
int f[N];
bool vis[N];
int Fa(int x)
{
return f[x]==x ? x : f[x]=Fa(f[x]);
}
bool solve()
{
memset(vis,0,sizeof(vis));
for (int i=1; i<N; i++)
f[i]=i;
int u,v,fu,fv,cnt=0,num=0;
int flag=1;
while (1) {
scanf("%d%d",&u,&v);
if (u==0 && v==0) {
puts(flag && (cnt==num-1 || (cnt==0 && num==0)) ? "Yes" : "No");
return 1;
}
else if (u==-1 && v==-1) {
return 0;
}
//坑点:注意确认不是那种特殊指令之后才进行点边的计数操作
cnt++;
if (!vis[u]) {
num++;
vis[u]=true;
}
if (!vis[v]) {
num++;
vis[v]=true;
}
fu=Fa(u);
fv=Fa(v);
if (fu==fv) {
flag=0;
}
else {
f[fu]=fv;
}
}
return 1;
}
int main()
{
while (solve())
continue;
return 0;
}
/*
0 0
1 2
*/
13. POJ-1308 Is It A Tree?
#include <cstdio>
#include <cstring>
#define N 100005
int CNT;
int f[N];
bool vis[N];
int Fa(int x)
{
return f[x]==x ? x : f[x]=Fa(f[x]);
}
bool solve()
{
memset(vis,0,sizeof(vis));
for (int i=1; i<N; i++)
f[i]=i;
int u,v,fu,fv,cnt=0,num=0;
int flag=1;
while (1) {
scanf("%d%d",&u,&v);
if (u==0 && v==0) {
printf("Case %d ",++CNT);
puts(flag && (cnt==num-1 || (cnt==0 && num==0)) ? "is a tree." : "is not a tree.");
return 1;
}
else if (u==-1 && v==-1) {
return 0;
}
//坑点:注意确认不是那种特殊指令之后才进行点边的计数操作
cnt++;
if (!vis[u]) {
num++;
vis[u]=true;
}
if (!vis[v]) {
num++;
vis[v]=true;
}
fu=Fa(u);
fv=Fa(v);
if (fu==fv) {
flag=0;
}
else {
f[fu]=fv;
}
}
return 1;
}
int main()
{
while (solve())
continue;
return 0;
}
/*
0 0
1 2
*/