并查集
Feature
To manage the elements grouping, we adopt this kind of special data structure. And it's based on the tree data structure. There are two main operations.
- query whether \(a\) and \(b\) are in the same group.
- merge the group of \(a\) and \(b\).
OJ Practise
poj 1182
Reference1 挑战程序设计竞赛 p87
#include <iostream>
#include <cstdio>
#include <cstring>
const int maxn= 50000*3+5;
int par[maxn];
int rank[maxn]; // par represents the father nodes, and rank indicate how to merge two sets, higher rank means father
void Init(int n)
{
for (int i= 0; i< n; ++i){
par[i]= i;
}
memset(rank, 0, maxn*sizeof(int));
}
int Find(int x)
{
if (par[x]== x)
return x;
return par[x]= Find(par[x]);
}
void Merge(int x, int y)
{
x= Find(x);
y= Find(y);
if (x== y)
return;
if (rank[x]< rank[y]){
par[x]= y;
}
else{
par[y]= x;
if (rank[x]== rank[y]){
rank[x]++;
}
}
}
bool Same(int x, int y)
{
return Find(x)== Find(y);
}
int main()
{
int n, k, x, y, d;
int ans= 0;
scanf("%d %d", &n, &k);
Init(3*n);
while (k--){
scanf("%d %d %d", &d, &x, &y);
if (x<1 || x>n || y<1 || y>n){
++ans;
continue;
}
x-= 1;
y-= 1;
if (1== d){
if (Same(x, y+n) || Same(x, y+2*n)){
++ans;
}
else{
Merge(x, y);
Merge(x+n, y+n);
Merge(x+2*n, y+2*n);
}
}
else{
if (Same(x, y) || Same(x, y+2*n)){
++ans;
}
else{
Merge(x, y+n);
Merge(x+n, y+2*n);
Merge(x+2*n, y);
}
}
}
printf("%d\n", ans);
return 0;
}
Reference2 hzwer
however this code TLE 😉...
#include <iostream>
#include <cstdio>
#define ll long long
using namespace std;
const int maxn= 50005;
int n, m, ans;
int d[maxn], fa[maxn];
// Attention, d is the key array, it represents the
// relation with its father node
/**
* Module In Algorithm Competition
*/
int Read()
{
ll x= 0, f= 1;
char ch= getchar();
while ('0'>ch || '9'< ch){
if ('-'== ch){
f= -1;
ch= getchar();
}
}
while (ch>= '0' && ch<= '9'){
x= x*10+ ch-'0';
ch= getchar();
}
return x*f;
}
int Find(int x)
{
if (x== fa[x]){
return x;
}
int t= fa[x];
fa[x]= Find(fa[x]);
d[x]= (d[x]+d[t])%3;
// d[fa[x]] has changed because we call the Find(fa[x]) recursively
return fa[x];
}
void Merge(int x, int y, int f)
{
int fx= Find(x), fy= Find(y);
fa[fx]= fy;
d[fx]= (d[y]-f-d[x]+3)%3;
// think this use the vectors' addition and substraction
}
int main()
{
n= Read();
m= Read();
int f, u, v;
for (int i= 1; i<= n; ++i)
fa[i]= i;
ans= 0;
while (m--){
f= Read();
u= Read();
v= Read();
if (u>n || v>n || (f==2 && u==v)){
++ans;
}
else{
if (Find(u)== Find(v)){
if (1== f && d[u]!= d[v]){
++ans;
}
if (2==f && (d[u]+1)%3 != d[v]){
++ans;
}
}
else{
Merge(u, v, f-1);
}
}
}
printf("%d\n", ans);
return 0;
}
ZOJ 3261
This problem is quite different, because Union-Find Set doesn't support delete operation. And here is a reall amazing trick:Offline Storage, Reverse processing. Really funny!!!! But there are lots of details need to be noticed, I'm a stupid Ne...
#include <iostream>
#include <cstdio>
#include <cstring>
#include <utility>
#include <map>
#include <algorithm>
using namespace std;
const int maxn= 1e5+3;
const int maxq= 5e5+3;
int p[maxn], par[maxn];
map<pair<int, int>, int> bd;
pair<int, int> dis[maxq];
char req[maxq], odr[10];
int ans[maxq];
int Q[maxq];
void Init()
{
memset(p, 0, sizeof(p));
memset(par, 0, sizeof(par));
memset(req, 0, sizeof(req));
memset(ans, 0, sizeof(ans));
memset(Q, 0, sizeof(Q));
memset(dis, 0, sizeof(dis));
bd.clear();
}
int Find(int idx)
{
if (idx== par[idx]){
return idx;
}
return par[idx]= Find(par[idx]);
}
void Union(int x, int y)
{
x= Find(x);
y= Find(y);
if (x== y){
return;
}
if (p[x]> p[y] || (p[x]== p[y] && x<y)){
par[y]= x;
}
else{
par[x]= y;
}
}
int main()
{
int n, m, q, a, b;
int fst= 1;
while (EOF!= scanf("%d", &n)){
Init();
if (fst){
fst= 0;
}
else{
cout<<endl;
}
for (int i= 0; i< n; ++i){
scanf("%d", p+i);
par[i]= i;
}
scanf("%d", &m);
for (int i= 0; i< m; ++i){
scanf("%d %d", &a, &b);
if (a> b){
swap(a, b); //important!!!! I'm so dumb...
}
bd[pair<int, int>(a, b)]= 1;
}
scanf("%d", &q);
int ida= 0, idd= 0;
for (int i= 0; i< q; ++i){
cin>>odr;
req[i]= odr[0];
if ('d'== req[i]){
scanf("%d %d", &a, &b);
if (a> b){
swap(a, b);
}
dis[idd++]= pair<int, int>(a, b);
bd[pair<int, int>(a, b)]= 0;
}
else{
scanf("%d", &a);
ans[ida++]= a;
}
}
int len= ida;
for (map<pair<int, int>, int>:: iterator it= bd.begin(); bd.end()!= it; ++it){
if (it->second){
pair<int, int> tmp= it->first;
Union(tmp.first, tmp.second);
}
}
for (int i= q-1; 0<= i; --i){
if ('d'== req[i]){
pair<int, int> tmp= dis[--idd];
Union(tmp.first, tmp.second);
}
else{
int tmp= ans[--ida];
int fa= Find(tmp);
if (p[fa]> p[tmp]){
ans[ida]= fa;
}
else{
ans[ida]= -1;
}
}
}
for (int i= 0; i< len; ++i){
printf("%d\n", ans[i]);
}
}
return 0;
}
POJ 2524
Easy...
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
const int maxn= 5e5+3;
int par[maxn];
int rnk[maxn];
void Init(const int n)
{
memset(rnk, 0, sizeof(rnk));
for (int j= 0; j< n; ++j){
par[j]= j;
}
}
int Find(int sn)
{
if (par[sn]== sn){
return sn;
}
return par[sn]= Find(par[sn]);
}
bool Same(int x, int y)
{
return Find(x)== Find(y);
}
bool Union(int x, int y)
{
x= Find(x);
y= Find(y);
if (x== y){
return false;
}
if (rnk[x]< rnk[y]){
par[x]= y;
}
else{
par[y]= x;
if (rnk[x]== rnk[y]){
++rnk[x];
}
}
return true;
}
int main()
{
int n, m, kase= 0;
while (EOF!= scanf("%d %d", &n, &m) && (n || m)){
int a, b;
Init(n);
for (int i= 0; i< m; ++i){
scanf("%d %d", &a, &b);
if (Union(a, b)){
--n;
}
}
printf("Case %d: %d\n", ++kase, n);
}
return 0;
}
POJ 2236
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
const int maxn= 1e3+5;
struct Point{
int x, y;
int par, rnk;
int Dis2(const Point &b) const
{
return (x-b.x)*(x-b.x)+(y-b.y)*(y-b.y);
}
}Wifi[maxn];
bool rep[maxn];
int d;
void Init(const int N)
{
memset(Wifi, 0, sizeof(Wifi));
memset(rep, 0, sizeof(rep));
for (int i= 1; i<= N; ++i){
Wifi[i].par= i;
}
}
int Find(int sn)
{
if (sn== Wifi[sn].par){
return sn;
}
return Wifi[sn].par= Find(Wifi[sn].par);
}
void Union(int a, int b)
{
a= Find(a);
b= Find(b);
if (a== b){
return;
}
if (Wifi[a].rnk< Wifi[b].rnk){
Wifi[a].par= b;
}
else{
Wifi[b].par= a;
if (Wifi[a].rnk== Wifi[b].rnk){
++Wifi[a].rnk;
}
}
}
int main()
{
int N;
int pc, pc1;
char opr;
scanf("%d %d", &N, &d);
Init(N);
for (int i= 1; i<= N; ++i){
scanf("%d %d", &Wifi[i].x, &Wifi[i].y);
}
while (EOF!= scanf(" %c", &opr)){
if ('O'== opr){
scanf("%d", &pc);
rep[pc]= true;
for (int i= 1; i<= N; ++i){
if (rep[i] && (d*d)>= Wifi[pc].Dis2(Wifi[i])){
Union(i, pc);
}
}
}
else{
scanf("%d %d", &pc, &pc1);
if (Find(pc)== Find(pc1)){
cout<<"SUCCESS"<<endl;
}
else{
cout<<"FAIL"<<endl;
}
}
}
return 0;
}

浙公网安备 33010602011771号