3 条题解

  • 0
    @ 2024-10-9 20:29:08

    提供一个扩展并查集的做法,洛谷有原题。

    i+ni+n 来表示与 ii 相关的另一个值,从而以 2i2i 的空间来维护一个并查集。

    那么如何维护这个并查集呢?只要按照题目的意思就行了。比如 p,qp, q 是朋友,只需要合并 p,qp, q 。而如果是敌人,那么只需要合并 p+n,qp+n, qp,q+np, q+n

    而且敌人的敌人就是朋友,所以也可以套回来。

    int find(int x) { return fa[x]==x ? x : fa[x]=find(fa[x]) ; } // 路径压缩
    
    void link(int x, int y)  // 合并 x,y
    {
        int fx = find(x), fy = find(y);
        fa[fx] = fy;
    }
    
    void solve()
    {
        cin>>n>>m;
        F(i,1,2*n) fa[i] = i;  // 关键初始化
        F(i,1,m){
            char opt; int p,q;
            cin>>opt>>p>>q;
            if (opt=='0') {
                link(p, q); // 不需要合并敌人的原因是,朋友的敌人不一定是自己的敌人。
            }
            if (opt=='1') {
                link(p+n, q); link(q+n, p);
            }
        }
        int ans = 0;
        F(i,1,n) ans += fa[i]==i ; // 这样之后会形成一个森林(每棵树都是并查集建出来的树),只需要统计树根数量。
        cout<<ans<<endl;
    }
    
    • 0
      @ 2024-7-13 15:57:33

      关于题面的一些个人解释:

      • 我的敌人的敌人是我的朋友,意思是我的朋友的敌人的敌人不一定是我的敌人,只是字面意思,并非阵营大战。
      • 题面里的每个认识的人不是朋友就是敌人这句话,指的是两个【认识的人】!换言之,这座城市里还能有不认识的人(费孝通点了个赞)

      因为如果不是那样子的话,没有给定亲友关系的节点,如果在遇到一个【有敌人】的节点,就无法视为一个独立的团队了。而输出和楼下题解并不包含这个情况。

      举个例子,若城市中有3个人,给定一组关系,A和B是敌人,那么整个城市中最多只有2个团伙。

      因为如果C与A是朋友,那么只有2个团伙。而且如果C与A是敌人,那么C与B将会是朋友,仍然只有2个团伙。

      • 另外,题面或许应该保证不会出现某个团伙中,A与C是朋友,B与C是朋友,但A与C是敌人的情况。但是我不知道。

      如果下次遇到熟人社会的话,只需要在统计答案的时候查一下存不存在【有敌人】的节点,如果有的话孤立那些自闭症的节点就好了。如果不存在,那么只需要制造一个全对立的节点,让他自成一派,再孤立其他自闭症就好。

      • 0
        @ 2023-4-15 14:50:46

        就是多了一步合并敌人的敌人,别的基本就是板子 建议训练: tzhsojor洛谷连接(这两是一道题

        #include <bits/stdc++.h>
        #define int long long int
        
        using namespace std;
        
        const int N = 2e5 + 7;
        int n,m;
        int fa[N << 1],e[N];
        
        inline int read(){
        	int x = 0,f = 1;
        	char c = getchar();
        	for(;!isdigit(c);c = getchar())
        		if(c == '-')f = -1;
        	for(;isdigit(c);c = getchar())
        		x = (x << 1) + (x << 3) + c - '0';
        	return x * f;
        }
        
        int get(int x){
        	if(fa[x] == x)return x;
        	return fa[x] = get(fa[x]);
        }
        
        void merge(int x,int y){
        	x = get(x);
        	y = get(y);
        	fa[x] = y;
        }
        
        void print(int x,int y){
        	if(get(x) == get(y)) printf("Y\n");
        	else printf("N\n");
        }
        
        signed main(){
        	n = read();m = read();
        	
        	for(int i = 1;i <= n;i ++){
        		fa[i] = i;
        		fa[i + n] = i + n;
        	}
        	
        	for(int i = 1;i <= m;i ++){
        		int p = read(),x = read(),y = read();
        		if(!p) merge(x,y);
        		else{
        			if(!e[x]) e[x] = y;
        			else{
        				merge(e[x],y);
        			}
        			if(!e[y]) e[y] = x;
        			else{
        				merge(e[y],x);
        			}
        		}
        	}
        	
        	int tot = 0;
        	
        	for(int i = 1;i <= n;i ++) if(fa[i] == i) tot++;
        	printf("%lld",tot);
        	
        	return 0;
        }
        
        • 1

        信息

        ID
        395
        时间
        1000ms
        内存
        128MiB
        难度
        10
        标签
        递交数
        6
        已通过
        4
        上传者