zoukankan      html  css  js  c++  java
  • [51Nod 1515] 明辨是非

    Description

    (n)组操作,每组操作形式为(x;y;p)
    (p)(1)时,如果第(x)变量和第(y)个变量可以相等,则输出(YES),并限制他们相等;否则输出(NO),并忽略此次操作。
    (p)(0)时,如果第(x)变量和第(y)个变量可以不相等,则输出(YES),并限制他们不相等 ;否则输出(NO),并忽略此次操作。

    Input

    输入一个数(n)表示操作的次数((n<=10^5))
    接下来(n)行每行三个数(x;y;p) ((x,y<=10^8,0≤p≤1))

    Output

    对于(n)行操作,分别输出(n)(YES)或者(NO)

    Solution

    没想到假的启发式合并也能A题啊。。。
    正解其实跟考试时候的思路差不多
    但是不是维护每个联通块的大小
    因为有可能一个联通块大小比较小但是连出去的边有很多
    所以我们要换一种数据结构维护每个联通块连出去了多少条边
    用什么数据结构可以维护大小,快速查找两个元素是否有关系呢?
    嗯... (STL)(set) 是符合要求的 查询大小是 (O(1)) 的,查找是 (O(nlogn))
    所以我们用一个 (set) (s[i]) 表示以 (i) 为根的联通块连出去的边(这里连边表示规定两个联通块严格不相等)
    考虑操作
    如果要求两个变量相等,那么就在两个联通块的 (set) 里找是否存在一条边连到了对方,如果有,那么此条件无法满足。
    如果要求两个变量不相等,那么假设它们不在一个联通块里,需要合并这两个联通块,就要用到启发式合并了。
    注意到我们已经记录了两个联通块连出去边的个数了, 为了保证复杂度,一定是想让连边少的联通块合并到连边多的联通块里。这就是启发式合并了。

    Code

    #include<set>
    #include<map>
    #include<cstdio>
    #define N 100005
    
    int n,tot;
    int ques[N][5];
    int father[N<<1];
    std::map<int,int> mp;
    std::set<int> s[N<<1];
    
    int find(int x){
    	if(father[x]==x) return x;
    	return father[x]=find(father[x]);
    }
    
    signed main(){
    	scanf("%d",&n);
    	for(int x,y,i=1;i<=n;i++){
    		scanf("%d%d%d",&x,&y,&ques[i][3]);
    		if(!mp[x]) mp[x]=++tot;
    		if(!mp[y]) mp[y]=++tot;
    		ques[i][1]=mp[x];
    		ques[i][2]=mp[y];
    	}
    	for(int i=1;i<=tot;i++) father[i]=i;
    	for(int i=1;i<=n;i++){
    		int r1=find(ques[i][1]);
    		int r2=find(ques[i][2]);
    		if(ques[i][3]==1){
    			if(r1==r2) {puts("YES");continue;}
    			if(s[r1].find(r2)!=s[r1].end() or s[r2].find(r1)!=s[r2].end()){
    				puts("NO");
    				continue;
    			}
    			if(s[r1].size()>s[r2].size()) r1^=r2^=r1^=r2;
    			std::set<int>::iterator it;
    			for(it=s[r1].begin();it!=s[r1].end();it++)
    				s[r2].insert(*it),s[*it].insert(r2),s[*it].erase(r1);
    			father[r1]=r2;
    			puts("YES");
    		}
    		else{
    			if(r1==r2) {puts("NO");continue;}
    			if(s[r1].find(r2)!=s[r1].end() or s[r2].find(r1)!=s[r2].end()){
    				puts("YES");
    				continue;
    			}
    			s[r1].insert(r2);
    			s[r2].insert(r1);
    			puts("YES");
    		}
    	}
    	return 0;
    }
    
  • 相关阅读:
    java读取ldif文件并创建新的节点
    AngularJS的基本概念和用法
    前端开发环境需要的工具
    解决:使用ajax验证登录信息返回前端页面时,当前整个页面刷新。
    js中switch语句不执行
    使用html5中required属性
    H-ui.admin v3.1学习之路(一):导航栏信息无法在内容区显示
    解决:@Auarowired为null
    scrapy框架整理
    django项目的部署
  • 原文地址:https://www.cnblogs.com/YoungNeal/p/8991523.html
Copyright © 2011-2022 走看看