zoukankan      html  css  js  c++  java
  • #并查集 20.09.25

    并查集

    AcWing 836. 合并集合

    题目

    AcWing 836. 合并集合

    思路

    并查集

    答案

    #include <iostream>
    
    using namespace std;
    
    const int N = 100010;
    
    int p[N];
    
    int find(int x)
    {
        return p[x] == x ? p[x] : p[x] = find(p[x]);
        //这句活浓缩了很多东西哦
        //首先会把祖先返回;
        //其次还会将每一个点的父节点都变为祖先。
    }
    
    int main()
    {
        int n, m;
        scanf("%d%d", &n, &m);
        for (int i = 1; i <= n; i ++ ) p[i] = i;
    
        while (m -- )
        {
            char op[2];
            int a, b;
            scanf("%s%d%d", op, &a, &b);
            if (*op == 'M') p[find(a)] = find(b);
            else
            {
                if (find(a) == find(b)) puts("Yes");
                else puts("No");
            }
        }
    
        return 0;
    }
    

    AcWing 837. 连通块中点的数量

    题目

    AcWing 837. 连通块中点的数量

    思路

    就多了一个算和的情况嘛,
    每次只需要将一个 祖宗所在并查集的点数加上 另一个 祖宗 所在并查集的点数就好了;

    答案

    #include <iostream>
    using namespace std;
    
    const int N = 100010;
    
    int p[N];
    int sum[N];
    int a, b;
    string op;
    
    int find(int x){
        return p[x] == x ? p[x] : p[x] = find(p[x]);
    }
    
    int main(){
        int n, m;
        scanf("%d%d", &n, &m);
        for (int i = 1; i <= n; i ++ ) p[i] = i, sum[i] = 1;
    
        while (m -- )
        {
            cin >> op;
            if(op == "C"){
                scanf("%d%d", &a, &b);
                if(a != b){
                    int pa = find(a), pb = find(b);
                    if(pa != pb) sum[pb] += sum[pa], p[pa] = pb;
                }
            }
            
            else{
                if(op == "Q1"){
                    scanf("%d%d", &a, &b);
                    if(find(a) == find(b)) printf("Yes
    ");
                    else printf("No
    ");
                }
                else scanf("%d", &a), printf("%d
    ", sum[find(a)]);
            }
            
        }
    
        return 0;
    }
    

    AcWing 240. 食物链

    题目

    AcWing 240. 食物链

    思路

    ……
    题意大概就是,并查集里面的元素每三层分一组,每一组的同一位置 的元素为一类,然后要你判断句子对错;
    我们可以用一个d数组来记录这个点到祖宗节点的距离,然后%3 来判断它在某一组的哪一层,以此判断它是哪一类动物;
    于是我们只需要额外地记录当前点到祖宗节点的距离就可以了;

    如果描述的时候两个点不在同一个并查集之中,那么就合并,
    距离的处理就是用两个点合并前到各自祖宗的距离相减,得到的就是一个点的祖宗到合并后的新祖宗的距离;

    答案

    #include <bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    
    const int N = 5e5 + 10;
    int sum;
    int n, m, P;
    int p[N];
    int d[N];
    int find(int x){
    	if(x != p[x]){
    		int t = find(p[x]);
    		d[x] += d[p[x]];
    		p[x] = t;
    	}
    	return p[x];
    }
    
    
    int main(){
    // 	freopen("ttt.in", "r", stdin);
    // 	freopen("ttt.out", "w", stdout);
    	
    	int n, k;
        scanf("%d%d", &n, &k);
        for (int i = 1; i <= n; i ++ ) p[i] = i;
    
        while (k -- ){
        	int z, a, b;
            scanf("%d%d%d", &z, &a, &b);
            int pa = find(a), pb = find(b);
            if(a > n || b > n) sum ++;
            else{
                if (z == 1){
                	if(pa == pb && (d[a] - d[b]) % 3 ) sum ++;
                	else if(pa != pb){
                		p[pa] = pb;
                		d[pa] = d[b] - d[a];
                	} 
                	
                }
                else
                {
                	if(pa == pb && (d[a] - d[b] - 1) % 3) sum ++;
                	else if(pa != pb){  
                		p[pa] = pb;
        	       		d[pa] = d[b] + 1 - d[a];
                	}
                }
                
            }
            
        }
        cout << sum;
    	return 0;
    	
    }
    

    第二次 食物链(并查集)

    第二次刷题记录从这里来的

    AcWing 240. 食物链
    思路
    这个有点麻烦,题目描述得太烂了。
    ……
    题意大概就是,并查集里面的元素每三层分一组,每一组的同一位置 的元素为一类,然后要你判断句子对错;
    我们可以用一个d数组来记录这个点到祖宗节点的距离,然后%3 来判断它在某一组的哪一层,以此判断它是哪一类动物;
    于是我们只需要额外地记录当前点到祖宗节点的距离就可以了;

    如果描述的时候两个点不在同一个并查集之中,那么就合并,
    距离的处理就是用两个点合并前到各自祖宗的距离相减,得到的就是一个点的祖宗到合并后的新祖宗的距离;

    答案

    #include <bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    
    const int N = 5e5 + 10;
    int sum;
    int n, m, P;
    int p[N];
    int d[N];
    //这里每执行一次都会直接将祖宗节点作为所有在内节点的父节点,
    //其距离不会重复计算第二次,因为下一次就遍历不到之前的父节点了.
    int find(int x){
    	if(x != p[x]){
    		int t = find(p[x]);
    		d[x] += d[p[x]];
    		p[x] = t;
    	}
    	return p[x];
    }
    
    int main(){
    // 	freopen("ttt.in", "r", stdin);
    // 	freopen("ttt.out", "w", stdout);	
    	int n, k;
        scanf("%d%d", &n, &k);
        for (int i = 1; i <= n; i ++ ) p[i] = i;
    
        while (k -- ){
        	int z, a, b;
            scanf("%d%d%d", &z, &a, &b);
            int pa = find(a), pb = find(b);
            //假话
            if(a > n || b > n) sum ++;
            else{
            	//1代表同类
                if (z == 1){
    	            //d[a] - d[b]) % 3这里如果不是0就说明他们根本就不是同类的
                	if(pa == pb && (d[a] - d[b]) % 3 ) sum ++;
                	//这里用else if 是因为上面的if有两个判断句,
                	//用else 的话就是肯定了其它三种情况,
                	//然而我们需要处理的只是四种中的两种
                	else if(pa != pb){
                		p[pa] = pb;
                		//添加的时候由于还没有用到find()函数,所以并不会立即更新新连通块内所有点到其对应根节点的距离
                		//这时候就要先将之前的根节点到当前根节点的距离处理一下,
                		//下一次的find()就会更新新连通块内所有点到其根节点的距离了
                		d[pa] = d[b] - d[a];
                	} 
                	
                }
                //2代表a吃b
                else
                {
    	            //假话,说反了
                	if(pa == pb && (d[a] - d[b] - 1) % 3) sum ++;
                	else if(pa != pb){  
                		p[pa] = pb;
        	       		d[pa] = d[b] + 1 - d[a];
                	}
                }
                
            }
            
        }
        cout << sum;
    	return 0;
    	
    }
    
  • 相关阅读:
    如何在DBGrid中能支持多项记录的选择
    How to create a OnCellDblClick for Delphi's TDBGrid
    如何在DBGrid里实现Shift+“选择行”区间多选的功能!
    DBGrid中Shift多选
    代码校验工具 SublimeLinter 的安装与使用
    jquery压缩图片插件
    React 入门最好的实例-TodoList
    前端切图
    提升前端效率的方式
    单页面应用的痛点
  • 原文地址:https://www.cnblogs.com/yuanyulin/p/14026735.html
Copyright © 2011-2022 走看看