1 条题解

  • 1
    @ 2023-4-15 17:09:06

    正向删点删边太麻烦了怎么办?那就反向加边嘛!

    把每个团伙当作点,能联络就代表两者间有边相连,该点蔓延的连通块大小的就是危险程度。


    先用vector将边存储。再反向遍历n -> k 并加边 直至当前点(k)加边后的连通块大小大于等于n/2,输出k

    #include <bits/stdc++.h>
    #define int long long int
    
    using namespace std;
    
    const int N = 2e5 + 7;
    int n,m;
    int fa[N << 1],tot[N];
    vector<int> 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);
    	if(x != y){//注意判是否已经为一家,防止累加
    		fa[x] = y;
    		tot[y] += tot[x];
    	}
    }
    
    void print(int x,int y){
    	if(get(x) == get(y)) printf("Y\n");
    	else printf("N\n");
    }
    
    signed main(){
    	n = read();
    	
    	for(int i = 1;i <= n;i ++){
    		fa[i] = i;
    		tot[i] = 1;
    	}
    	
    	for(int i = 1;i <= n;i ++){
    		int k = read();
    		while(k --){
    			int j = read();
    			e[i].push_back(j);
    		}
    	}
    	
    	for(int i = n;i > 0;i --){
    		for(int j = 0;j < e[i].size();j ++)
    			if(e[i][j] > i) merge(e[i][j],i);
    		if(tot[get(i)] > (n / 2)){
    			printf("%lld",i);
    			return 0;
    		}
    	}
    	return 0;
    }
    

    类似题目:星球大战(反向加边 + 并查集)

    • 1

    信息

    ID
    396
    时间
    1000ms
    内存
    128MiB
    难度
    10
    标签
    递交数
    3
    已通过
    2
    上传者