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;
    	
    }
    
  • 相关阅读:
    vue自定义指令
    ZOJ Problem Set–2104 Let the Balloon Rise
    ZOJ Problem Set 3202 Secondprice Auction
    ZOJ Problem Set–1879 Jolly Jumpers
    ZOJ Problem Set–2405 Specialized FourDigit Numbers
    ZOJ Problem Set–1874 Primary Arithmetic
    ZOJ Problem Set–1970 All in All
    ZOJ Problem Set–1828 Fibonacci Numbers
    要怎么样调整状态呢
    ZOJ Problem Set–1951 Goldbach's Conjecture
  • 原文地址:https://www.cnblogs.com/yuanyulin/p/14026735.html
Copyright © 2011-2022 走看看