前提

在这道题老师讲过之后,再考时,我还是WA了ヽ(*。>Д<)o゜果然,我还是好菜啊~%?…,# *'☆&℃$︿★?

谢谢Jack_Pei dalao的帮忙。~~O(∩_∩)O~~

正文

在我这台机子上,直接由网址上到题目会出现 NOFIND404 所以这一次希望看题解的你可以自己动手丰衣足食去找到这道题

首先,这题一看要维护关系,且数据范围不小时,就想到了并查集&&离散化

相等关系具有传递性,即a==b&&b==c等价于a==c。所以当我们在维护相等关系时,我们会使用并查集。每次找到根节点,再合并一下,就相当于维护了相等关系。即我是你爸爸的儿子,你也是你的爸爸的儿子,我们自然地位也就相等——都是爸爸的儿子

但,由某本数学书,我们可以知道,a!=b&&b!=c不等价于a!=c。即你是你爸爸的儿子,我不是你爸爸的儿子,可是我却是你爸爸的女儿,但我们地位还是一样的——都是爸爸的孩子。但是a==b&&b!=c等价于a!=c。所以此时我们就希望去给每一个并查集中的节点维护这一个不等的关系,表示这些数和它不等。而其既可以合并,又可以快捷查询,简便操作,显然vector,,set中选择一个(map常数大,用它弊大于利,优点没有其他更加明显。优先队列无法做到便捷的插入删除与寻找)。而最后应该用set。

理由如下

Vector动态开四倍空间,相当于在最坏的情况下,一半的节点上,你明明只占用了五万多一点的大小,动态内存却开到二十万,且中间有许多重复的数字。你会MLE(机房某位dalao曾现身说法过)

Set可以避免空间太大,重复数字。查询,插入均是logn的时间复杂度,也可以接受。

再说Setd的合并——启发式合并。其实就是每次合并把数字少的那组合并到数字多的那组以达到减少树的深度及合并次数而达到减少时间复杂度的效果。具体的图就不放了,自己看看其他oier的就好了

实现思路大致是,询问不等时,若两位数字所在的源头不同,则二个数字可以不同。分别在与他们相同的源头处限制它们互相相等。询问相等时,若两数字所在源头中维护不相等的set中没有对方的,则代表他们可以想等。此时,若两个数字出处一致则毫无大碍,否则就需要把数字少的源头的不等关系转嫁。即某人父亲和一个有孩子的离异女子结婚时,她的孩子也是他的孩子。即我们所说的启发式合并。

十分愉快的代码时间

(其实代码里我也打了很多注释)

 #include<iostream>
 #include<set>
 #include<cstdio>
 #include<map>
 using namespace std;
 //从全局变量->主程序->随着主程序看函数是个好习惯
 map<long long,long long>q;//离散化要用
 struct ziji{
     long long fa;//这个地方的父亲
     set<long long> s;//要维护的不等关系
     #define fa(i) mn[i].fa
     #define s(i) mn[i].s
 }mn[];
 long long x,y,p,n,ff;//见主函数分析
 inline long long father(long long i){
     if(i==fa(i)) return i;
     else return fa(i)=father(fa(i));
     //简单的按秩合并
 }
 void message1(long long a,long long b){
     long long root=father(a),root1=father(b);
     // 找爸爸
     if(s(root).find(root1)==s(root).end()) {//可以不等
         putchar('Y'),putchar('E'),putchar('S'),putchar('\n');
         //这里一定要用putchar 或 puts ,用cout&&printf会超时
         //反正我超时了
         if(root!=root1){//非同源
             if(s(root).size()>s(root1).size()) swap(root,root1);
             //小的合并到大的里头去——启发式合并
             fa(root)=root1;
             set<long long>::iterator it=s(root).begin();
             for(it;it!=s(root).end();it++)
                 s(root1).insert(*it),s(*it).insert(root1),s(*it).erase(root);
                 //暴力合并set
         }
     }
     else putchar('N'),putchar('O'),putchar('\n');
 }
 void message2(long long a,long long b){//维护不等关系
     int root=father(a),root1=father(b);
     //找爸爸
     if(root!=root1){//不相等
         putchar('Y'),putchar('E'),putchar('S');putchar('\n');
         s(root).insert(root1);s(root1).insert(root);
         //二位父亲互不相等
     }
     else putchar('N'),putchar('O'),putchar('\n');
 }
 void chuli(int v){
     //初始并查集时,由于仅仅是操作数是n
     //最惨就是每次都是俩不同的,所以i<=v*2
     ;i<=v*;i++) fa(i)=i;
 }
 int main(){
     scanf("%lld",&n);
     chuli(n);//初始并查集
     ;i<=n;i++){
         scanf("%lld%lld%lld",&x,&y,&p);
         //下面就是离散化处理了,我这里用了map
         //据另一位大佬说,这里可以用sort+去重离线做
         //但我更喜欢map,有本事打我啊
         if(!q.count(x)){//如果这个数之前没有出现过
             ff++;//一共出现的数总数++
             q[x]=ff;x=ff;//以后这个数再调用就是ff,此时这个数离散成了ff
         }else x=q[x];//出现了,就是当时被离散的值
         if(!q.count(y)){//同理
             ff++;
             q[y]=ff;y=ff;
         }else y=q[y];
         ) message1(x,y);
         ) message2(x,y);
     }
     ;//功德圆满,我好困啊
 }

代码

国际惯例

如果有什么疑问,请在我的博客下留言,或者看题解刚开始我给的那个大佬的博客,他似乎也写了。我会尽我的努力为您提供答案。虽然可能不及时,希望可以谅解。thankyou for your attention

 
 
 
 
 
 

题解51nod1515——明辨是非的更多相关文章

  1. [51nod1515]明辨是非

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

  2. 51nod1515 明辨是非 并查集 + set

    一开始想的时候,好像两个并查集就可以做......然后突然懂了什么.... 相同的并查集没有问题,不同的就不能并查集了,暴力的来个set就行了..... 合并的时候启发式合并即可做到$O(n \log ...

  3. 51nod-1515 明辨是非——并查集

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

  4. 51nod 1515 明辨是非 启发式合并

    1515 明辨是非 题目连接: https://www.51nod.com/onlineJudge/questionCode.html#!problemId=1515 Description 给n组操 ...

  5. 51Nod 1515 明辨是非 —— 并查集 + 启发式合并

    题目链接:http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1515 1515 明辨是非  题目来源: 原创 基准时间限制:1 ...

  6. 2016 华南师大ACM校赛 SCNUCPC 非官方题解

    我要举报本次校赛出题人的消极出题!!! 官方题解请戳:http://3.scnuacm2015.sinaapp.com/?p=89(其实就是一堆代码没有题解) A. 树链剖分数据结构板题 题目大意:我 ...

  7. noip2016十连测题解

    以下代码为了阅读方便,省去以下头文件: #include <iostream> #include <stdio.h> #include <math.h> #incl ...

  8. BZOJ-2561-最小生成树 题解(最小割)

    2561: 最小生成树(题解) Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 1628  Solved: 786 传送门:http://www.lyd ...

  9. Codeforces Round #353 (Div. 2) ABCDE 题解 python

    Problems     # Name     A Infinite Sequence standard input/output 1 s, 256 MB    x3509 B Restoring P ...

随机推荐

  1. Java Thread系列(一)线程创建

    Java Thread系列(一)线程创建 Java 中创建线程主要有三种方式:继承 Thread.实现 Runnable 接口.使用 ExecutorService.Callable.Future 实 ...

  2. oj 1002题 (大数题)

    #include <stdio.h> #include <string.h> int main(void) { int q,j,h,k,l; int d; ],s2[];//题 ...

  3. HDU 4511 小明系列故事——女友的考验 (AC自动机 + DP)

    小明系列故事——女友的考验 Time Limit: 500/200 MS (Java/Others)    Memory Limit: 65535/32768 K (Java/Others)Total ...

  4. 项目中使用WCF替换asmx Web service总结

    以前项目解决方案中,用http协议的asmx Web service作服务器数据访问入口,在SoapHeader中写入用户名和加盐密码进行身份认证. http asmx服务是明文传输,传输过程中数据很 ...

  5. IE(IE6/IE7/IE8)支持HTML5标签

    让IE(ie6/ie7/ie8)支持HTML5元素,我们需要在HTML头部添加以下JavaScript,这是一个简单的document.createElement声明,利用条件注释针对IE来调用这个j ...

  6. 用Swift实现一款天气预报APP(一)

    这个系列的目录: 用Swift实现一款天气预报APP(一) 用Swift实现一款天气预报APP(二) 用Swift实现一款天气预报APP(三) Swift作为现在苹果极力推广的语言,发展的非常快.这个 ...

  7. 自定义View--滚动View

    实现这么一个效果,一个布局中有一个View,那个View会随着我们手指的拖动而滑动,这种效果该如何实现?   我们第一反应应该是自定义一个DragView类继承View,然后重写onTouchEven ...

  8. java并发编程实战:第七章----取消与关闭

    Java没有提供任何机制来安全地终止线程(虽然Thread.stop和suspend方法提供了这样的机制,但由于存在缺陷,因此应该避免使用 中断:一种协作机制,能够使一个线程终止另一个线程的当前工作 ...

  9. Objective-C 学习笔记(四) 数组

    Objective-C 数组作为函数参数传递 如果想在一个函数作为参数,通过一维数组,就必须声明函数形式参数 方式一    指针作为形式参数 - (void) myFunction(int *) pa ...

  10. PPI协议(西门子PLCS7-200)

    西门子PLC S7-200 PPI协议报文,9600,偶校验,8数据位,1停止位 读取vb100寄存器:PC发送报文68 1B 1B 68 2 0 6C 32 1 0 0 0 0 0 E 0 0 4 ...