并查集专题

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", 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\n");
            else printf("FAIL\n");
        }
        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\n",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("\n");
        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\n",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\n");
                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\n");
            else {
                for(int i=0; i<cnt; i++) {
                    if(pre[vis[i]] == vis[i]) ans++;
                }
                if(ans == 1) printf("Yes\n");
                else printf("No\n");
            }
        }
    }
    return 0;
}
posted @ 2019-07-16 23:52  小饭hhh  阅读(170)  评论(0编辑  收藏  举报