【并查集】并查集进阶

P1892团伙
一开始想不到的操作。除并查集数组外,开一个数组记录x的敌人(的集合),实现合并敌人的敌人的工作。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
#include<cstdio>
#include<iostream>
using namespace std;
const int MAXN=1005;
int a[MAXN],b[MAXN]={0};

int find(int x){
if(x!=a[x])a[x]=find(a[x]);
return a[x];
}

void unite(int x,int y){
a[find(x)]=find(y);
}

bool same(int x,int y){
return find(x)==find(y);
}

int main(){
int n,m;
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
a[i]=i;
char t;
int x,y;
for(int i=1;i<=m;i++){
cin>>t>>x>>y;
if(t=='F'){
if(!same(x,y)){
unite(x,y);
n--;
}
}
if(t=='E'){
if(b[x]!=0){
if(!same(b[x],y)){
unite(b[x],y);
n--;
}
}
else b[x]=find(y);
if(b[y]!=0){
if(!same(b[y],x)){
unite(b[y],x);
n--;
}
}
else b[y]=find(x);
}
}
printf("%d\n",n);
return 0;
}

P1525关押罪犯
原理是贪心,先排序,从最大的一个个试,直到无法保证两个集合为止。对与合并“敌人”操作的实现还是与上题相同。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
#include<cstdio>
#include<algorithm>
#include<iostream>
using namespace std;
#define x(i) (g[i].st)
#define y(i) (g[i].ed)
const int MAXN=20005,MAXM=100005;
int a[MAXN],b[MAXN]={0};
struct edge{
int st,ed,val;
};
edge g[MAXM];


bool cmp(edge a,edge b){
return a.val>b.val;
}

int find(int x){
if(x!=a[x])a[x]=find(a[x]);
return a[x];
}

void unite(int x,int y){
a[find(x)]=find(y);
}

bool same(int x,int y){
return find(x)==find(y);
}

int main(){
int n,m;
int i;

scanf("%d%d",&n,&m);
for(int i=0;i<m;i++){
scanf("%d%d%d",&g[i].st,&g[i].ed,&g[i].val);
}

sort(g,g+m,cmp);

for(i=1;i<=n;i++)
a[i]=i;

for(i=0;i<=m;i++){
if(same(x(i),y(i)))
break;

if(b[x(i)]==0){
b[x(i)]=y(i);
}
else{
unite(b[x(i)],y(i));
}

if(b[y(i)]==0){
b[y(i)]=x(i);
}
else{
unite(b[y(i)],x(i));
}

}

printf("%d\n",g[i].val);
return 0;
}

P2024食物链

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
#include<iostream>
#include<cstdio>
#include<cstdlib>
using namespace std;
const int MAXN=50005;
int a[MAXN],d[MAXN]={0};

int find(int x){
int fa=a[x];
if(x!=a[x]){
a[x]=find(a[x]);
d[x]=(d[x]+d[fa])%3;
}
return a[x];
}

void unite(int x,int y){
a[a[x]]=a[y];
}

int main(){
int n,k,x,y,z,cnt=0;
scanf("%d%d",&n,&k);
for(int i=1;i<=n;i++)a[i]=i;

for(int i=1;i<=k;i++){
scanf("%d%d%d",&z,&x,&y);
if(x>n||y>n){
cnt++;
continue;
}
if(z==2&&x==y){
cnt++;
continue;
}

if(z==1){
if(find(x)!=find(y)){
d[a[x]]=(d[y]-d[x]+3)%3;
unite(x,y);
}
else{
if(d[x]!=d[y])cnt++;
}
}
else{
if(find(x)!=find(y)){
d[a[x]]=(d[y]-d[x]+4)%3;
unite(x,y);
}
else{
if(d[a[x]]!=(d[y]-d[x]+4)%3)cnt++;
}
}

}

printf("%d",cnt);
return 0;
}