题目链接:http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1515

题目来源: 原创
基准时间限制:1 秒 空间限制:131072 KB 分值: 160 难度:6级算法题
 收藏
 关注

给n组操作,每组操作形式为x y p。

当p为1时,如果第x变量和第y个变量可以相等,则输出YES,并限制他们相等;否则输出NO,并忽略此次操作。

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

Input
输入一个数n表示操作的次数(n<=1*10^5)
接下来n行每行三个数x,y,p(x,y<=1*10^8,p=0 or 1)
Output
对于n行操作,分别输出n行YES或者NO
Input示例
3
1 2 1
1 3 1
2 3 0
Output示例
YES
YES
NO

题解:

1.一开始还以为跟这题POJ2492 A Bug's Life一样,直接种类并查集即可,结果连测试数据都过不了。后来发现:当A!=B, B!=C时,A可能等于C,也可能不等于C,而对于POJ2492,因为元素只有两种,所以A肯定等于C。自己就是受这一题的影响,一直认为A肯定等于C,思想僵化……

2.所以,同一个集合里的元素只能是相等的,即不能用种类并查集了。对此的解决策略是:为每个集合添加一个与之不相等集合的队列。

3.当规定两个集合不相等时,只需各自把对方加入到自己的“不相等”队列即可;当规定两集合相等时,即需要合并两集合,此时,就需要用到启发式合并了:把“不相等”队列小的合并到“不相等”队列大的集合上。

4.启发式合并的时间复杂度为:O(nlogn),证明:每一次把小集合合并到大集合上,则新集合的大小至少为小集合的两倍,即表明每合并一次,集合的大小可翻倍,由于只有n个元素,那么最多只能有logn次翻倍;每一次翻倍,最多只能有n个元素参与,所以时间复杂度为O(nlogn)。

5.在检验两集合是否不相等时,由于还用到了find()函数,所以总体的时间复杂度为:O(n*logn*logn)

代码如下:

 #include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
#include <cmath>
#include <queue>
#include <stack>
#include <map>
#include <string>
#include <set>
using namespace std;
typedef long long LL;
const int INF = 2e9;
const LL LNF = 9e18;
const int MOD = 1e9+;
const int MAXN = 2e5+; int fa[MAXN];
map<int,int>M; //用于离散化
vector<int>s[MAXN]; //记录与这个变量不相等的变量
int find(int x)
{
return fa[x]==-?x:fa[x]=find(fa[x]);
} bool Union(int u, int v, int w)
{
u = find(u);
v = find(v); if(u==v) //如果在同一个集合,即两变量相等,则直接判断
return (w==);
else //不在同一个集合
{
if(s[u].size()>s[v].size()) swap(u,v);
bool flag = false; //判断两变量是否不相等
int sz = s[u].size();
for(int i = ; i<sz; i++) //用小的集合去判断
{
flag |= find(s[u][i])==v; //s[u][i]可能已经被合并到某个集合,所以要找到其当前所在的集合
if(flag) break; //加上这个判断,不然被卡常数
} if(flag) //不过两变量不相等,则直接判断,并返回
return (w==);
else if(w==) //否则,如果要求两变量相等,则两者所在的集合
{
fa[u] = v;
sz = s[u].size();
for(int i = ; i<sz; i++) //启发式合并的关键
s[v].push_back(s[u][i]);
s[u].clear();
}
else //如果要求两变量不相等,则各自把对方加入到自己的“不相等”队列
{
s[u].push_back(v);
s[v].push_back(u);
}
}
return true;
} int main()
{
int n, m;
while(scanf("%d",&n)!=EOF)
{
M.clear();
m = ;
memset(fa,-,sizeof(fa));
for(int i = ; i<MAXN; i++)
s[i].clear();
for(int i = ; i<=n; i++)
{
int u,v,w;
scanf("%d%d%d",&u,&v,&w);
if(M.find(u)==M.end()) M[u] = ++m;
if(M.find(v)==M.end()) M[v] = ++m; if(Union(M[u],M[v],!w)) puts("YES");
else puts("NO");
}
}
}

51Nod 1515 明辨是非 —— 并查集 + 启发式合并的更多相关文章

  1. 51nod 1515 明辨是非 [并查集+set]

    今天cb巨巨突然拿题来问,感觉惊讶又开心,希望他早日康复!!坚持学acm!加油! 题目链接:51nod 1515 明辨是非 [并查集] 1515 明辨是非 题目来源: 原创 基准时间限制:1 秒 空间 ...

  2. 51nod 1515 明辨是非 并查集+set维护相等与不等关系

    考试时先拿vector瞎搞不等信息,又没离散化,结果好像MLE:后来想起课上讲过用set维护,就开始瞎搞迭代器...QWQ我太菜了.. 用并查集维护相等信息,用set记录不相等的信息: 如果要求变量不 ...

  3. 51nod 1515 明辨是非 并查集 + set + 启发式合并

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

  4. BZOJ2733[HNOI2012]永无乡——线段树合并+并查集+启发式合并

    题目描述 永无乡包含 n 座岛,编号从 1 到 n,每座岛都有自己的独一无二的重要度,按照重要度可 以将这 n 座岛排名,名次用 1 到 n 来表示.某些岛之间由巨大的桥连接,通过桥可以从一个岛 到达 ...

  5. BZOJ 4668: 冷战 并查集启发式合并/LCT

    挺好想的,最简单的方法是并查集启发式合并,加暴力跳父亲. 然而,这个代码量比较小,比较好写,所以我写了 LCT,更具挑战性. #include <cstdio> #include < ...

  6. [HDU 3712] Fiolki (带边权并查集+启发式合并)

    [HDU 3712] Fiolki (带边权并查集+启发式合并) 题面 化学家吉丽想要配置一种神奇的药水来拯救世界. 吉丽有n种不同的液体物质,和n个药瓶(均从1到n编号).初始时,第i个瓶内装着g[ ...

  7. [BZOJ 4668]冷战(带边权并查集+启发式合并)

    [BZOJ 4668]冷战(并查集+启发式合并) 题面 一开始有n个点,动态加边,同时查询u,v最早什么时候联通.强制在线 分析 用并查集维护连通性,每个点x还要另外记录tim[x],表示x什么时间与 ...

  8. 51 nod 1515 明辨是非(并查集合并)

    1515 明辨是非题目来源: 原创基准时间限制:1 秒 空间限制:131072 KB 分值: 160 难度:6级算法题 给n组操作,每组操作形式为x y p. 当p为1时,如果第x变量和第y个变量可以 ...

  9. BZOJ 3673: 可持久化并查集(可持久化并查集+启发式合并)

    http://www.lydsy.com/JudgeOnline/problem.php?id=3673 题意: 思路: 可持久化数组可以用可持久化线段树来实现,并查集的查询操作和原来的一般并查集操作 ...

随机推荐

  1. Linux中ping不通外网

    在linux中ping www.baidu.com 无法ping通 需要修改vi /etc/resolv.conf 增加如下内容: nameserver 114.114.114.114 nameser ...

  2. 2017.2.28 activiti实战--第七章--Spring容器集成应用实例(五)普通表单

    学习资料:<Activiti实战> 第七章  Spring容器集成应用实例(五)普通表单 第六章中介绍了动态表单.外置表单.这里讲解第三种表单:普通表单. 普通表单的特点: 把表单内容写在 ...

  3. Log4cplus入门

    Log4cplus使用指南 1.  Log4cplus简单介绍 log4cplus是C++编写的开源的日志系统,前身是java编写的log4j系统.受Apache Software License保护 ...

  4. 登陆界面综合实例+spinner下拉列表框详解

      点击确定: 点击修改:     想到Spinner下拉按钮可以通过两种方法生成 方法一: 1.在array数组里面定义数组 代码如下: <resources> <st <? ...

  5. OC中动态创建可变数组的问题.有一个数组,数组中有13个元素,先将该数组进行分组,每3个元素为一组,分为若干组,最后用一个数组统一管理这些分组.(要动态创建数组).两种方法

    <span style="font-size:24px;">//////第一种方法 // NSMutableArray *arr = [NSMutableArray a ...

  6. MySQL 原理性

    1.MySQL的复制原理以及流程 (1).复制基本原理流程 1. 主:binlog线程——记录下所有改变了数据库数据的语句,放进master上的binlog中: 2. 从:io线程——在使用start ...

  7. LeetCode222——Count Complete Tree Nodes

    Given a complete binary tree, count the number of nodes. Definition of a complete binary tree from W ...

  8. Java线程:概念及原理

    线程是执行的程序中的一个线程. Java虚拟机允许应用程序必须同时运行多个执行线程. 每个线程都有一个优先事项.具有更高优先级的线程优先于线程的优先级较低的执行.每个线程可能会或可能不会也被标记为一个 ...

  9. 消息队列Handler的用法

    下面是每隔一段时间就执行某个操作,直到关闭定时操作: final Handler handler = new Handler(); Runnable runnable = new Runnable() ...

  10. python 基础 2.6 for 循环 和if循环 中break

    python中最基本的语法格式大概就是缩进了.python中常用的循环:for循环,if循环.一个小游戏说明for,if ,break的用法. 猜数字游戏: 1.系统生成一个20以内的随机数 2.玩家 ...