• 洛谷 P3377 【模板】左偏树(可并堆)


    2019-06-01

    题目: 洛谷 P3377 【模板】左偏树(可并堆): https://www.luogu.org/problemnew/show/P3377


    题目描述

    如题,一开始有N个小根堆,每个堆包含且仅包含一个数。接下来需要支持两种操作:

    操作1: 1 x y 将第x个数和第y个数所在的小根堆合并(若第x或第y个数已经被删除或第x和第y个数在用一个堆内,则无视此操作)

    操作2: 2 x 输出第x个数所在的堆最小数,并将其删除(若第x个数已经被删除,则输出-1并无视删除操作)

    输入输出格式

    输入格式:

    第一行包含两个正整数N、M,分别表示一开始小根堆的个数和接下来操作的个数。

    第二行包含N个正整数,其中第i个正整数表示第i个小根堆初始时包含且仅包含的数。

    接下来M行每行2个或3个正整数,表示一条操作,格式如下:

    操作1 : 1 x y

    操作2 : 2 x

    输出格式:

    输出包含若干行整数,分别依次对应每一个操作2所得的结果。

    输入输出样例

    输入样例#1:
    5 5
    1 5 4 2 3
    1 1 5
    1 2 5
    2 2
    1 4 2
    2 2
    输出样例#1:
    1
    2
    

    说明

    当堆里有多个最小值时,优先删除原序列的靠前的,否则会影响后续操作1导致WA。

    时空限制:1000ms,128M

    数据规模:

    对于30%的数据:N<=10,M<=10

    对于70%的数据:N<=1000,M<=1000

    对于100%的数据:N<=100000,M<=100000

    样例说明:

    初始状态下,五个小根堆分别为:{1}、{5}、{4}、{2}、{3}。

    第一次操作,将第1个数所在的小根堆与第5个数所在的小根堆合并,故变为四个小根堆:{1,3}、{5}、{4}、{2}。

    第二次操作,将第2个数所在的小根堆与第5个数所在的小根堆合并,故变为三个小根堆:{1,3,5}、{4}、{2}。

    第三次操作,将第2个数所在的小根堆的最小值输出并删除,故输出1,第一个数被删除,三个小根堆为:{3,5}、{4}、{2}。

    第四次操作,将第4个数所在的小根堆与第2个数所在的小根堆合并,故变为两个小根堆:{2,3,5}、{4}。

    第五次操作,将第2个数所在的小根堆的最小值输出并删除,故输出2,第四个数被删除,两个小根堆为:{3,5}、{4}。

    故输出依次为1、2。


    首先,这道题目标题便很明确地告诉我们——这是一道模板题。

    是模板题,就应该从理论出发,普及常识,最后得到一长串代码(疯狂背诵)

    但在这里,我是不会讲左偏树的基本姿势滴..(其实我也不会),如有需要,自行百度~~~~~~~~~~

    我在这里介绍的是“pbds”(平板电视)的解法?

    不知道 pbds的同学请戳这里这里还有这里

    那么显而易见,这道题一下子没有了难度。或许有些童鞋已经参照 pbds的姿势做出来了。

    既然大家都会了,那么直接上代码:

     1 //
     2 #include <bits/stdc++.h>
     3 #include <ext/pb_ds/priority_queue.hpp>
     4 using namespace std;
     5 using namespace __gnu_pbds;
     6 typedef unsigned long long ll;
     7 #define ri register ll
     8 
     9 struct A
    10 {
    11     ll x;
    12     ll rank;
    13     bool operator< (const A& p)const
    14     {
    15         if(x==p.x)
    16         {
    17             return rank>p.rank;
    18         }
    19         return x>p.x;
    20 //        */
    21     }
    22 };
    23 
    24 __gnu_pbds::priority_queue<A,less<A>,pairing_heap_tag> q[100005];
    25 ll n,m;
    26 ll father[100005];
    27 bool vis[100005];
    28 
    29 ll findf(ll a)
    30 {
    31     ri k=a;
    32     while(father[k]!=k)
    33     {
    34         k=father[k];
    35     }
    36     father[a]=k;
    37     return k;
    38 }
    39 
    40 void joinf(ll x,ll y)
    41 {
    42     ri xx=findf(x);
    43     ri yy=findf(y);
    44     father[yy]=xx;
    45 }
    46 
    47 signed main()
    48 {
    49     ios::sync_with_stdio(0),cin.tie(0);
    50     cin>>n>>m;
    51     for(ri i=1;i<=n;i++)
    52     {
    53         ri p;cin>>p;
    54         q[i].push((A){p,i});
    55         father[i]=i;
    56     }
    57     
    58     for(ri i=1;i<=m;i++)
    59     {
    60         ri rerinput;cin>>rerinput;
    61         if(rerinput==1)
    62         {
    63             ri x,y;cin>>x>>y;
    64             ri xx=findf(x);
    65             ri yy=findf(y);
    66             if(q[xx].size()>q[yy].size())swap(xx,yy);
    67             q[xx].join(q[yy]);
    68             joinf(xx,yy);
    69         }
    70         else if(rerinput==2)
    71         {
    72             ri k;cin>>k;
    73             if(vis[k])
    74             {
    75                 cout<<-1<<'
    ';
    76                 continue;
    77             }
    78             ri wh=findf(k);
    79             cout<<q[wh].top().x<<'
    ';
    80             vis[q[wh].top().rank]=1;
    81             q[wh].pop();
    82         }
    83     }
    84     
    85 //    */
    86     return 0;
    87 }
    88 //

    然后开森的得到下面的结果:

    好好好。

    我的错,我的错。

    一定又是哪里让我给遗漏了。

    那再重审一次题目:我发现我遗漏了操作一后面小括号里的内容。

    于是重新改一次,增加了66,67行的内容

     1 //
     2 #include <bits/stdc++.h>
     3 #include <ext/pb_ds/priority_queue.hpp>
     4 using namespace std;
     5 using namespace __gnu_pbds;
     6 typedef unsigned long long ll;
     7 #define ri register ll
     8 
     9 struct A
    10 {
    11     ll x;
    12     ll rank;
    13     bool operator< (const A& p)const
    14     {
    15         if(x==p.x)
    16         {
    17             return rank>p.rank;
    18         }
    19         return x>p.x;
    20 //        */
    21     }
    22 };
    23 
    24 __gnu_pbds::priority_queue<A,less<A>,pairing_heap_tag> q[100005];
    25 ll n,m;
    26 ll father[100005];
    27 bool vis[100005];
    28 
    29 ll findf(ll a)
    30 {
    31     ri k=a;
    32     while(father[k]!=k)
    33     {
    34         k=father[k];
    35     }
    36     father[a]=k;
    37     return k;
    38 }
    39 
    40 void joinf(ll x,ll y)
    41 {
    42     ri xx=findf(x);
    43     ri yy=findf(y);
    44     father[yy]=xx;
    45 }
    46 
    47 signed main()
    48 {
    49     ios::sync_with_stdio(0),cin.tie(0);
    50     cin>>n>>m;
    51     for(ri i=1;i<=n;i++)
    52     {
    53         ri p;cin>>p;
    54         q[i].push((A){p,i});
    55         father[i]=i;
    56     }
    57     
    58     for(ri i=1;i<=m;i++)
    59     {
    60         ri rerinput;cin>>rerinput;
    61         if(rerinput==1)
    62         {
    63             ri x,y;cin>>x>>y;
    64             ri xx=findf(x);
    65             ri yy=findf(y);
    66             if(vis[x]||vis[y])continue;
    67             if(xx==yy)continue;
    68             if(q[xx].size()>q[yy].size())swap(xx,yy);
    69             q[xx].join(q[yy]);
    70             joinf(xx,yy);
    71         }
    72         else if(rerinput==2)
    73         {
    74             ri k;cin>>k;
    75             if(vis[k])
    76             {
    77                 cout<<-1<<'
    ';
    78                 continue;
    79             }
    80             ri wh=findf(k);
    81             cout<<q[wh].top().x<<'
    ';
    82             vis[q[wh].top().rank]=1;
    83             q[wh].pop();
    84         }
    85     }
    86     
    87 //    */
    88     return 0;
    89 }
    90 //

    然后愉快地过了。↑↑↑↑↑↑↑↑↑↑AC代码↑↑↑↑↑↑↑↑↑↑

    但是!!!

    -----看一看题解

    dalao们已经讲得很详细了(根本没看懂)

    从茫茫代码里,我发现了一个重要的一句话——————

    ——————dalao又做粗了结论性的发言

     我一下子豁然开朗,去掉了上面代码里的路径压缩

    结果:

    额~~好吧,我又不知道是为什么了

    但我这个代码似乎是需要路径压缩滴。

    小结:

    这篇随笔告诉我们——看题要仔细,题目给出的限制一定要考虑!

    除此外再AC代码第68行:“if(q[xx].size()>q[yy].size())swap(xx,yy);”这个似乎必须 q[xx].size() < q[yy].size()。

    但实话说,我也不是很清楚,

    如果有dalao知道,还望指教~~

  • 相关阅读:
    How To Build CyanogenMod Android for smartphone
    CentOS安装Code::Blocks
    How to Dual boot Multiple ROMs on Your Android SmartPhone (Upto Five Roms)?
    Audacious——Linux音乐播放器
    How to Dual Boot Multiple ROMs on Your Android Phone
    Everything You Need to Know About Rooting Your Android Phone
    How to Flash a ROM to Your Android Phone
    什么是NANDroid,如何加载NANDroid备份?
    Have you considered compiled a batman-adv.ko for android?
    BATMAN—Better Approach To Mobile Adhoc Networking (B.A.T.M.A.N.)
  • 原文地址:https://www.cnblogs.com/Vty66CCFF/p/10958223.html
Copyright © 2020-2023  润新知