• 带权并查集|连通、集合最值、集合元素个数、到根的距离、等级辈分


    带权并查集

    两道题合起来,说清楚并查集的作用有哪些

    ①连通、集合最值、集合元素个数、到根的距离...

    #include<bits/stdc++.h>
    using namespace std;
    
    /*查找、合并|统计集合个数、集合最大值、每个集合的元素个数、到根的距离*/
    
    const int maxn = 1e6+10;
    
    int n,m;
    int father[maxn]; 
    int size[maxn];//集合中元素的个数 
    int maxs[maxn];//集合中最大值 
    int dist[maxn];//到根节点的距离 
    int setNums = 0;
    
    void init(){
    	for(int i=1;i<=n;i++){
    		father[i] = i;
    		size[i] = 1;
    		maxs[i] = i;
    		dist[i] = 0;
    	}
    }
    
    //find循环写法 
    int Find(int x){
    	int p,tmp;
    	p = x;
    	while(father[x] != x){
    		x = father[x];//找到祖先节点 
    	}
    	while(p!=x){//更新p(原x)的父辈节点 的父辈为祖先(x) 
    		tmp = father[p];
    		father[p] = x;
    		p = tmp;
    	}
    	return x;
    }
    
    //递归写法 
    int find(int x){
    	if(father[x] == x){
    		return x;
    	}	
    	int y = father[x];
    	father[x] = find(y);
    	dist[x] += dist[y];//更新x到根节点的距离 
    	return father[x];
    }
    
    //合并 
    void join(int x,int y){
    	int a = find(x);
    	int b = find(y);
    	if(a!=b){
    		father[a] = b;
    		dist[a] = size[b];//更新子集合的根到 父集合根 的距离 
    		size[b] += size[a];//更新父亲集合的元素个数
    		maxs[b] = max(maxs[a],maxs[b]);
    	}
    }
    
    int main(){
    	cin>>n>>m;//元素数 操作数
    	init();
    	char ins[20];
    	setNums = n;
    	for(int i=0;i<m;i++){
    		int x,y;
    		scanf("%s",ins);
    		if(ins[0] == 'u'){
    			cin>>x>>y;
    			if(find(x) != find(y)){
    				join(x,y);//合并 
    				setNums--;//合并一次 集合数-1 
    			}
    		}else if(ins[0] == 's' && ins[1] == 'a'){
    			cin>>x>>y;
    			int fx = find(x);
    			int fy = find(y);//查找是否连接 (在同一集合) 
    			if(fx==fy) cout<<1<<endl;
    			else cout<<0<<endl; 
    		}else if(ins[0] == 'n'){
    			cin>>x;
    			cout<<size[find(x)]<<endl;//查询当前集合中元素的数量 
    		}else if(ins[0] == 'm'){
    			cin>>x;
    			cout<<maxs[find(x)]<<endl;//查询当前集合中的最大值 
    		}else if(ins[0] == 's' && ins[1] =='e'){
    			cout<<setNums<<endl;//查询 集合总数 
    		}else{
    			cin>>x;
    			find(x);
    			cout<<dist[x]<<endl;//打印x到它的集合的根 的距离 
    //			cout<<size[x]-1-dist[x]<<endl;//查询排(与根的距离)在与x同一集合中 x后的有多少人 
    		}
    	} 
    	return 0;
    } 
    

    ②另外一类,求辈分(等级)问题,也可以用并查集做(路径压缩find函数中记录rank等级)。就是建一颗树,dfs、bfs都可以完成。

    2016天梯赛

    2018天梯赛

    2018找辈分等级代码:

    并查集
    #include <iostream>
    #include <vector>
    using namespace std;
    const int maxn=1e6 + 10;
     
    int father[maxn];//记录父辈 
    int rank[maxn];//记录等级 
    int vis[maxn];//标记是否查询过 
     
    vector<int> vt[maxn];//存储每个辈分级别下的 元素 
    
    //路径压缩 递归累加rank等级 
    int find(int x)
    {
        if(vis[x])
            return rank[x];
        vis[x]=1;
        if(x!=-1)//不是根节点 
            rank[x] += find(father[x]);//等级 加上 父亲节点的辈分 
        return rank[x];
    }
    
    int main()
    {
        int n;
        cin>>n;
        for(int i=1;i<maxn;i++)
        {
            father[i]=i;
            rank[i]=1;
        }
        for(int i=1;i<=n;i++)
        {
            int k;
            scanf("%d",&k);
            father[i]=k;
        }
        int max1=-1;
        for(int i=1;i<=n;i++)
        {
            int kk=find(i);
            if(kk>max1)
            {
                max1=kk;
                vt[max1].push_back(i);
            }
            else if(kk==max1)
                vt[max1].push_back(i);
        }
        printf("%d
    ",max1);
        for(int i=0;i<vt[max1].size();i++)
        {
            if(!i) printf("%d",vt[max1][i]);
            else printf(" %d",vt[max1][i]);
        }
        return 0;
    }
    
    
    bfs
    #include<bits/stdc++.h> //L2-026. 小字辈(bfs stl)
    using namespace std;    //没什么好讲的  就bfs
    const int maxn = 1e5 + 5;//虽然队友简单粗暴递归dfs也过了 限时是真的宽容啊
    int level[maxn], fat[maxn];//这个fat原来是想辅助标记父亲节点的 后来发现不用了
    set<int>ans, son[maxn];//简单粗暴set存儿子节点和答案 stl大法好
    int main(){
        int n, fa, i, maxl, t, top, f;
        cin >> n;
        for(i = 1; i <= n; i ++){//读入 全部把对应的子节点扔到对应的set里
            cin >> t;
            if(t == -1)
                fa = i;
            else{
                fat[i] = t;
                son[t].insert(i);
            }
        }
        level[fa] = 1;
        queue<int>q;
        q.push(fa);
        maxl  = 1;
        while(!q.empty()){//bfs一遍 找到最小辈分
            top = q.front();
            q.pop();
            set<int>::iterator it;
            for(it = son[top].begin(); it != son[top].end(); it ++){
                q.push(*it);
                level[*it] = level[top] + 1;
            }
            maxl = max(maxl, level[top]);
            // cout << top << " ";
        }
        //for(i = 1; i <= n ; i ++)
            // cout << level[i] << " ";
        cout << maxl << endl;
        f = 0;
        q.push(fa);//注意这个push
        while(!q.empty()){//再bfs一遍 存答案排序
            top = q.front();
            q.pop();
            set<int>::iterator it;
            for(it = son[top].begin(); it != son[top].end(); it ++){
                q.push(*it);
            }
            if(level[top] == maxl)
                ans.insert(top);
        }
        set<int>::iterator it;//输出
        for(it = ans.begin(); it != ans.end(); it ++){
            if(f) cout << " ";
            else f = 1;
            cout << *it;
        }
        return 0;
    }
    
    
    dfs
    #include <iostream>
    #include <vector>
    #include <set>
    using namespace std;
    int maxlevel = 1;
    vector<int > v[100010];
    set<int> s;
    void dfs(int node, int level) {
        if (level > maxlevel) {
            maxlevel = level;
            s.clear();
            s.insert(node);
        } else if (level == maxlevel) {
            s.insert(node);
        }
        for (int i = 0; i < v[node].size(); i++)
            dfs(v[node][i], level+1);
    }
    int main() {
        int n, num, root = 0;
        cin >> n;
    //    v.resize(n+1);
        for (int i = 1; i <= n; i++) {
            cin >> num;
            if (num == -1) {
                root = i;
                continue;
            }
            v[num].push_back(i);
        }
        dfs(root, 1);//从根出发建树 
        cout << maxlevel << endl;
        for (set<int>::iterator it = s.begin(); it != s.end(); it++) {
            if (it != s.begin()) cout << " ";
            cout << *it;
        }
        return 0;
    }
    

    更多

    https://blog.csdn.net/floraqiu/article/details/79226320

  • 相关阅读:
    01.Markdown学习
    微信小程序开发基础
    如何在本地搭建微信小程序服务器
    Golang | 报错
    Golang | 扩展
    Golang | 基础
    Golang | 基础
    Golang | 基础
    Chrome——书签同步码云
    Rustlings_structs
  • 原文地址:https://www.cnblogs.com/fisherss/p/10536488.html
Copyright © 2020-2023  润新知