2019.7.15
并查集专题
HDU 1213
并查集裸题,把一些点连起来,问有多少个pre[i] = i;
#include <cstdio>
#include <cstring>
int pre[1010];
int findn(int son) {
int root = son;
while(son != pre[son]) son = pre[son];
while(root != son) {
int t = pre[root];
pre[root] = son;
root = t;
}
return son;
}
int main() {
int t;
scanf("%d", &t);
while(t--) {
int n, m, a, b;
scanf("%d %d", &n, &m);
for(int i = 1; i <= n; i++) pre[i] = i;
while(m--) {
scanf("%d %d", &a, &b);
a = findn(a);
b = findn(b);
if(a != b) {
pre[a] = b;
n--;
}
}
printf("%d
", n);
}
return 0;
}
POJ 2236
给出一些电脑的坐标,如果电脑被修好了,那么和他距离d以内的被修好的电脑就能和他相连,如果a和b相连,b和c相连,那么a和c也相连,询问两台电脑是否相连
注意输出SUCCESS,FAIL
#include <cstdio>
#include <cstring>
struct node
{
int x, y;
}a[1010];
int pre[1010];
int findn(int son) {
int root = son;
while(son != pre[son]) son = pre[son];
while(root != son) {
int t = pre[root];
pre[root] = son;
root = t;
}
return son;
}
bool flag[1010];
int main() {
memset(flag, false, sizeof(flag));
int n, d, b, c;
char s[2];
scanf("%d %d", &n, &d);
for(int i = 1; i <= n; i++) {
scanf("%d %d", &a[i].x, &a[i].y);
pre[i] = i;
}
while(~scanf("%s", s)) {
if(s[0] == 'S') {
scanf("%d %d", &b, &c);
if(findn(b) == findn(c)) printf("SUCCESS
");
else printf("FAIL
");
}
else {
scanf("%d", &b);
if(flag[b] == false) {
flag[b] = true;
for(int i = 1; i <= n; i++) {
if(flag[i] == true && (a[i].x - a[b].x)*(a[i].x - a[b].x) + (a[i].y - a[b].y) * (a[i].y - a[b].y) <= d*d) {
int root1 = findn(b);
int root2 = findn(i);
if(root1 != root2) pre[root1] = root2;
}
}
}
}
}
return 0;
}
HDU 3038
给出多个区间的和,区间的元素可以是负数,如果输入的区间和不合理就lies++;
最后输出lies;
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int N=200050;
int n,m;
int fa[N],rankk[N];
int findd(int x)
{
if(x==fa[x])return x;
int temp=fa[x];
fa[x]=findd(fa[x]);
rankk[x]+=rankk[temp];
return fa[x];
}
bool unite(int x,int y,int c)
{
int xx=findd(x),yy=findd(y);
if(xx==yy)
{
if(rankk[y]!=rankk[x]+c) return false;
return true;
}
fa[yy]=xx;
rankk[yy]=rankk[x]-rankk[y]+c;
return true;
}
int main()
{
while(~scanf("%d%d",&n,&m))
{
int lies = 0;
for(int i=0;i<=n;i++) {
fa[i]=i;
rankk[i]=0;
}
while(m--)
{
int a,b,c;
scanf("%d%d%d",&a,&b,&c);
if(a>b) swap(a,b);
if(!unite(a-1,b,c)) lies++;
}
printf("%d
",lies);
}
return 0;
}
ZOJ 3261
有n个星球,这些星球都有一个能力值,只有能力值小的可以向能力值大的星球求助,这些星球本来有是相连的,下面可以进行两种操作,第一种是查询该星球可以向哪个星球求助,第二种是破坏某两个星球的路。
#include<cstdio>
#include<cstring>
#include<map>
using std:: map;
const int maxn = 10010;
const int maxm = 20010;
const int maxk = 50010;
int par[maxn], pow[maxn];
map<int, int>mp[maxn];
bool vis[maxm];
struct node
{
int bol, a, b;
};
node ope[maxk];
struct nodee
{
int a, b;
};
nodee side[maxm];
int fid(int x) {
int son, temp;
son = x;
while(x != par[x]) x = par[x];
while(son != x) {
temp = par[son];
par[son] = x;
son = temp;
}
return x;
}
void swap(int *a, int *b) {
int c;
c = *a;
*a = *b;
*b = c;
}
void con(int x, int y) {
int fx = fid(x);
int fy = fid(y);
if(pow[fx] > pow[fy]) par[fy] = fx;
else if(pow[fx] == pow[fy])
{
if(fx<=fy) par[fy] = fx;
else par[fx] = fy;
}
else par[fx] = fy;
}
int main()
{
int n, m, k, a, b, flag = 0;
char s[50];
while(~scanf("%d", &n)) {
if(flag) printf("
");
else flag = 1;
memset(vis, false, sizeof(vis));
for(int i = 0; i < n; i++) {
scanf("%d", &pow[i]);
par[i] = i;
mp[i].clear();
}
scanf("%d", &m);
for(int i = 0; i < m; i++) {
scanf("%d %d", &a, &b);
if(a > b) swap(&a, &b);
side[i].a = a;
side[i].b = b;
mp[a][b] = i;
vis[i] = true;
}
scanf("%d", &k);
for(int i = 0; i < k; i++) {
scanf("%s", s);
if(s[0] == 'q') {
ope[i].bol = 1;
scanf("%d", &ope[i].a);
}
else {
ope[i].bol = 2;
scanf("%d %d", &a, &b);
if (a > b) swap(&a, &b);
ope[i].a = a;
ope[i].b = b;
vis[mp[a][b]] = false;
}
}
for(int i = 0; i<m; i++) {
if(vis[i]) {
con(side[i].a, side[i].b);
}
}
int cnt = 0, ans[k];
for(int i = k - 1; i >= 0; i--) {
if(ope[i].bol == 1) {
int x=ope[i].a;
int f=fid(x);
if(pow[f] > pow[x]) ans[cnt++] = f;
else ans[cnt++] = -1;
}
else {
con(ope[i].a, ope[i].b);
}
}
for(int i = cnt - 1; i >= 0; i--)
printf("%d
",ans[i]);
}
return 0;
}
HDU 1272
查询是否存在环且每个点是否能连通。
#include <cstdio>
int pre[100010];
int findn(int son) {
int root = son;
while(son != pre[son]) son = pre[son];
while(root != son) {
int t = pre[root];
pre[root] = son;
root = t;
}
return son;
}
int main() {
int a, b;
while(1) {
int flag = 0, vis[100010], cnt = 0;
bool bol[100010];
for(int i = 1; i < 100010; i++) pre[i] = i, bol[i] = false;
while(1) {
scanf("%d %d", &a, &b);
if(a == 0 && b == 0 && cnt == 0) {
printf("Yes
");
continue;
}
if((a == 0 && b == 0) || (a == -1 && b == -1)) {
break;
}
if(bol[a] == false) vis[cnt++] = a;
if(bol[b] == false) vis[cnt++] = b;
bol[a] = bol[b] = true;
if(flag == 0) {
a = findn(a);
b = findn(b);
if(a == b) {
flag = 1;
}
else pre[a] = b;
}
}
int ans = 0;
if(a == -1 && b == -1) break;
else {
if(flag) printf("No
");
else {
for(int i=0; i<cnt; i++) {
if(pre[vis[i]] == vis[i]) ans++;
}
if(ans == 1) printf("Yes
");
else printf("No
");
}
}
}
return 0;
}