zoukankan      html  css  js  c++  java
  • 牛客-小w的魔术扑克【并查集】

    正题

    题目链接:https://ac.nowcoder.com/acm/contest/1100/C


    题目大意

    (n)个数字(m)张扑克牌,每张两面有各有一个数字,可以选择一些扑克牌使用正面的数字,一些使用反面的,(q)次询问能否凑出(lsim r)

    (1leq n,m,qleq 10^5)


    解题思路

    每张牌看成连接两个点的一条边,那么显然如果一个大小为(k)的连通块,有(k)条或以上的边那么肯定能抽出整个联通块。

    而如果是(k-1)条边,那么这棵树最多有一个数字无法被抽出,所以包括整棵树的区间不合法,并查集处理出这些区间判断即可。

    时间复杂度:(O(nalpha (n)))


    code

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    const int N=1e5+10;
    int n,m,fa[N],w[N],siz[N],l[N],r[N],mx[N];
    int find(int x)
    {return (fa[x]==x)?x:(fa[x]=find(fa[x]));}
    int main()
    {
    	scanf("%d%d",&n,&m);
    	for(int i=1;i<=n;i++)fa[i]=i,siz[i]=1;
    	for(int i=1,x,y;i<=m;i++){
    		scanf("%d%d",&x,&y);
    		x=find(x),y=find(y);
    		if(x==y){w[x]++;continue;}
    		fa[x]=y;w[y]+=w[x]+1;
    		siz[y]+=siz[x];
    	}
    	memset(l,0x3f,sizeof(l));
    	for(int i=1;i<=n;i++){
    		int x=find(i);
    		l[x]=min(l[x],i);
    		r[x]=max(r[x],i);
    	}
    	for(int i=1;i<=n;i++){
    		if(find(i)==i){
    			if(w[i]!=siz[i]-1)continue;
    			mx[r[i]]=max(mx[r[i]],l[i]);
    		}
    	}
    	for(int i=1;i<=n;i++)
    		mx[i]=max(mx[i-1],mx[i]);
    	scanf("%d",&m);
    	while(m--){
    		int l,r;
    		scanf("%d%d",&l,&r);
    		if(l>mx[r])puts("Yes");
    		else puts("No");
    	}
    	return 0;
    }
    
  • 相关阅读:
    出现Unexpected token, expected ","报错原因
    select属性的作用
    程序员无广告版百度
    VUE核心组件
    ajax的作用
    SSH整合
    Unity安装教程
    bean的生命周期
    BeanFactory
    打印机
  • 原文地址:https://www.cnblogs.com/QuantAsk/p/15347714.html
Copyright © 2011-2022 走看看