zoukankan      html  css  js  c++  java
  • [离散化模板][并查集][洛谷1955]程序自动化分析

    开篇 

    这是很久之前做过的题了,也是我第一次接触离散化的题。之前一直忘了记下来,今天补写一篇离散化博客。 

    题目

    原链接:https://www.luogu.com.cn/problem/P1955

     

    (懒得复制粘贴再改格式了,大家直接看吧)

     

    解说

    最开始看过一遍题这东西简单的一批啊,并查集板子吧。先处理相等关系,相等的扔到一个集子里,然后判断不等关系,每个不等关系中的两个数要是在一个集子里就不成立,一遍判断下来啥事没有就成立。又能水过一道题了哈哈哈!

     

    开始一写,笑容渐渐凝固在脸上:等一下这个数的大小小于等于1e9,我的father数组开不下啊[托腮][托腮]。最开始还不会离散化,想的是开几个int数组,用要存的数%每个数组的大小,分开储存。比如开10个1e8的数组,100000005就存在第二个数组第五个,10就存在第一个数组第十个这样的。后来一想出题人肯定不会是想让我们这样的,极大的可能会卡个内存啥的,这种方法实际上的内存是没有改变的,所以估计会被卡掉,而且极其麻烦。

     

    再仔细看一看,题目中n<=1e6,描述的每个关系涉及两个数,那么最多就涉及2000000个数,那么就相当于1e9的储存空间中有大部分是空着的,简直是在浪费空间,能优化吗?显然可以,在这个题中,我们需要的只是区分每一个数,而不需要每个数的具体大小,那么我们是不是就可以把一些大一点的数用小一点的数代替呢?就像暗号一样,反正最后只要保证每个数有专属于它的暗号,可以区分就可以了。这就是离散化。

     

    那么具体该怎么做呢?毕竟之前没接触过离散化所以此时我在网上一顿搜索应该情有可原

     

    那么,离散化一共包括三部。一、排序。二、去重。三、映射。下面一步一步讲解。

     排序

    这是非常简单的一步。一边读入一边把所有涉及到的数字存在all数组里,然后sort排序就行了(P.S. 可以顺便在这里特判一下一个不等关系都没有就直接YES然后continue)。

     1 cin>>n;
     2 memset(all,0,sizeof(all));
     3 int judge=0;
     4 for (int i=1;i<=n;i++){
     5     cin>>cun[i].a>>cun[i].b>>cun[i].inf;
     6     if(!cun[i].inf) judge=1;
     7         all[tot]=cun[i].a; tot++;
     8     all[tot]=cun[i].b; tot++;
     9 }
    10 if(!judge){cout<<"YES"<<endl;continue;}
    11 sort(all+1,all+tot);

    去重及映射

    这就是之前不会的原因了,这部分涉及两个之前没接触过的函数lower_bound()和unique()(都属于algorithm库)。unique的作用是“去掉”容器中重复元素(不一定要求数组有序),它会把重复的元素添加到容器末尾(所以数组大小并没有改变),而返回值是去重之后的尾地址(因此我们可以相当于地认为数组大小变成了unique(all+1,all+tot)-all-1,后面的元素就都相当于被抹掉了,那么我们就得到了一个本题涉及的所有数的不重复列表,这样的话我们就可以把一个数的下标直接当成它的“暗号”),而函数lower_bound()在first和last中的前闭后开区间进行二分查找,返回大于或等于val的第一个元素位置。如果所有元素都小于val,则返回last的位置(注意它返回的也是位置),通过lower_bound()我们就可快速找到一个数在all数组中的位置,然后储存起来它的下标了。

    1 int cnt=unique(all+1,all+tot)-all-1;
    2 for (int i=1;i<=n;i++){
    3     cun[i].a=lower_bound(all+1,all+cnt+1,cun[i].a)-all;
    4     cun[i].b=lower_bound(all+1,all+cnt+1,cun[i].b)-all;
    5 }

    最后

    最后就直接跑并查集就行了。我认为这就不用再说了吧。

    完整代码

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 int all[2000002],fa[20000002];
     4 struct u{
     5     int a,b,inf;
     6 }cun[20000002];
     7 bool cmp(u a,u b){
     8     return a.inf>b.inf;
     9 }
    10 int find(int x){
    11     if(fa[x]==x) return x;
    12     return fa[x]=find(fa[x]);
    13 }
    14 int main(){
    15     ios::sync_with_stdio(false);
    16     int t;
    17     cin>>t;
    18     while(t--){
    19         int n,tot=1;
    20         cin>>n;
    21         memset(all,0,sizeof(all));
    22         int judge=0;
    23         for (int i=1;i<=n;i++){
    24             cin>>cun[i].a>>cun[i].b>>cun[i].inf;
    25             if(!cun[i].inf) judge=1;
    26             all[tot]=cun[i].a; tot++;
    27             all[tot]=cun[i].b; tot++;
    28         }
    29         if(!judge){cout<<"YES"<<endl;continue;}
    30         sort(all+1,all+tot);
    31         int cnt=unique(all+1,all+tot)-all-1;
    32         for (int i=1;i<=n;i++){
    33             cun[i].a=lower_bound(all+1,all+cnt+1,cun[i].a)-all;
    34             cun[i].b=lower_bound(all+1,all+cnt+1,cun[i].b)-all;
    35         }
    36         for (int i=1;i<=cnt+1;i++) fa[i]=i;
    37         int js=0;
    38         sort(cun+1,cun+1+n,cmp);
    39         while(1){
    40             js++;
    41             if(!cun[js].inf) break;
    42             int xx=find(cun[js].a),yy=find(cun[js].b);
    43             if(xx!=yy) fa[xx]=yy;
    44         }
    45         int ans=1;
    46         for (int i=js;i<=n;i++){
    47             int xx=find(cun[i].a),yy=find(cun[i].b);
    48             /*cout<<xx<<' '<<yy<<endl;*/
    49             if(xx==yy){
    50                 ans=0;
    51                 break;
    52             }
    53         }
    54         if(ans) cout<<"YES"<<endl;
    55         else cout<<"NO"<<endl;
    56     }
    57     return 0;
    58 } 
    View Code

    结语

     这大概是我自学的最好的一回了。unique()和lower_bound()都彻彻底底地查了用法,离散化可以说学清楚了。或许,这就是所谓的“超越教练员”必经的一步吧。

     幸甚至哉,歌以咏志。

  • 相关阅读:
    java各种框架的比较,分析
    HTTP请求响应码
    jersey获取各个参数的总结
    web项目中各种路径的获取
    netsh学习
    解决sqlplus: command not found
    win10 提速
    解决win10 64位系统可用2.99g
    Windows10关闭SearchUI.exe进程的方法
    msf payload
  • 原文地址:https://www.cnblogs.com/DarthVictor/p/12449064.html
Copyright © 2011-2022 走看看