基本思路:

首先按照weightA升序排序,然后依次在图中加边,并维护起点到终点路径上weightB的最大值

如果加边过程中生成了环,则删除环中weightB最大的边

由于是无向图,点之间没有拓扑序,所以在建立LCT模型时,可以将原图的边也视为点,这样就转化成了维护路径上的点权最大值(Orz Hzwer)

点的连通性可以用并查集维护

AC code:(其实Splay双旋一次时只需要进行3次update,而代码中舍弃了这个优化)

 #include <cstdio>
 #include <cstring>
 #include <algorithm>

 ;
 ;
 const int inf=0x3f3f3f3f;

 struct Edge
 {
     int u,v;
     int weightA,weightB;

     void assign(int _u,int _v,int _wa,int _wb)
     {
         u=_u; v=_v; weightA=_wa; weightB=_wb;
     }
     bool operator < (const Edge& other) const
     {
         return this->weightA < other.weightA;
     }
 };

 Edge elist[maxM];

 inline int getMaxIdx(int u,int v)
 {
     return elist[u].weightB > elist[v].weightB ? u : v;
 } //Let elist[0].weightB = -inf

 struct Splay
 {
     int idx;
     int maxIdx;
     bool rev;
     Splay* child[];
     Splay* parent;

     void init(int id)
     {
         idx=maxIdx=id;
         rev=false;
         child[]=child[]=parent=;
     }
     bool isRoot()
     {
         if(!parent) return true;
         ] && ];
     }
     void update()
     {
         maxIdx=idx;
         ]) maxIdx=getMaxIdx(]->maxIdx);
         ]) maxIdx=getMaxIdx(]->maxIdx);
     }
     void reverse()
     {
         if(!isRoot()) parent->reverse();
         if(rev) {
             std::swap(child[],child[]);
             ]) child[]->rev ^= ;
             ]) child[]->rev ^= ;
             ;
         }
     }
     ; }
     void rotate(int dir)
     {
         Splay* temp=parent;
         this->parent=temp->parent;
         if(parent)
         {
             ]) parent->child[]=this;
             ]) parent->child[]=this;
         }
         temp->child[dir^]=this->child[dir];
         if(child[dir]) child[dir]->parent=temp;
         child[dir]=temp;
         temp->parent=this;
         temp->update();
         this->update();
     }
     void splay()
     {
         reverse();
         while(!isRoot())
         {
             );
             ]) st|=;
             ;
             if(!parent->isRoot())
             {
                 ]) st|=;
                 ;
             }
             switch(st)
             {
             : rotate(); break;
             : rotate(); break;
             : parent->rotate(); ); break;
             : rotate(); rotate(); break;
             : rotate(); rotate(); break;
             :parent->rotate(); ); break;
             }
         }
     }
 };

 Splay node[maxN+maxM];

 int access(int idx)
 {
     Splay *cur,*last;
     ;cur;last=cur,cur=cur->parent)
     {
         cur->splay();
         cur->child[]=last;
         cur->update();
     }
     return last->maxIdx;
 }
 inline void setAsRoot(int idx)
 {
     access(idx);
     node[idx].splay();
     node[idx].setRev();
 }
 inline void link(int u,int v)
 {
     setAsRoot(u);
     node[u].parent=node+v;
 }
 inline void cut(int u,int v)
 {
     setAsRoot(u);
     access(v);
     node[v].splay();
     node[v].child[]=node[u].parent=;
     node[v].update();
 }
 inline int query(int u,int v)
 {
     setAsRoot(u);
     return access(v);
 }

 int N,M;
 int center[maxN];

 int getCenter(int idx)
 {
     return center[idx]==idx ? idx :
         center[idx]=getCenter(center[idx]);
 }
 void input()
 {
     scanf("%d%d",&N,&M);
     int u,v,wa,wb;
     ;i<=M;i++)
     {
         scanf("%d%d%d%d",&u,&v,&wa,&wb);
         if(u==v) { --i; --M; }
         else elist[i].assign(u,v,wa,wb);
     }
 }
 void init()
 {
     elist[].weightB=-inf;
     std::sort(elist+,elist+M+);
     ;i<=M;i++) node[i].init(i);
     ;i<=N;i++) node[i+M].init();
     ;i<=N;i++) center[i]=i;
 }
 void addEdge(int e)
 {
     int& u=elist[e].u;
     int& v=elist[e].v;
     int cu=getCenter(u);
     int cv=getCenter(v);
     if(cu!=cv)
     {
         link(e,M+u);
         link(e,M+v);
         center[cu]=cv;
     }
     else {
         int mx=query(M+u,M+v);
         if(elist[e].weightB < elist[mx].weightB)
         {
             cut(mx,M+elist[mx].u);
             cut(mx,M+elist[mx].v);
             link(e,M+u);
             link(e,M+v);
         }
     }
 }
 int solve()
 {
     int ans(inf);
     init();
     ;i<=M;i++)
     {
         addEdge(i);
         )==getCenter(N))
         {
             ,M+N);
             ans=std::min(ans,elist[i].weightA+elist[mx].weightB);
         }
     }
     :ans;
 }

 int main()
 {
     input();
     printf("%d\n",solve());
     ;
 }

——————分割线——————

这道题我Debug了2天共计5h,最后偶然间查明了死因居然是——

 #ifdef WRONG_SPLAY_CODE
 void Splay::splay()
 {
     reverse();
     while(!isRoot())
     {
         );
         ]) st|=;
         ;
         if(!parent->isRoot())
         {
             ]) st|=;
             ;
         }
         switch(st)
         {
         : rotate(); break;
         : rotate(); break;
         : parent->rotate(); ); break;
         : rotate(); rotate(); break;
         : rotate(); rotate(); break;
         :parent->rotate(); ); break;
         }
     }
 }
 #endif

I FELL COLLAPSED BECAUSE OF THIS

不过在Debug期间,参考了不少其他神犇的AC代码,也学到了各种姿势,算是因祸得福吧……

Vijos1865 NOI2014 魔法森林 LCT维护生成树的更多相关文章

  1. P2387 [NOI2014]魔法森林 LCT维护最小生成树

    \(\color{#0066ff}{ 题目描述 }\) 为了得到书法大家的真传,小 E 同学下定决心去拜访住在魔法森林中的隐 士.魔法森林可以被看成一个包含 n 个节点 m 条边的无向图,节点标号为 ...

  2. 【BZOJ 3669】 [Noi2014]魔法森林 LCT维护动态最小生成树

    这道题看题意是在求一个二维最小瓶颈路,唯一可行方案就是枚举一维在这一维满足的条件下使另一维最小,那么我们就把第一维排序利用A小的边在A大的情况下仍成立来动态加边维护最小生成树. #include &l ...

  3. [Luogu P2387] [NOI2014]魔法森林 (LCT维护边权)

    题面 传送门:https://www.luogu.org/problemnew/show/P2387 Solution 这题的思想挺好的. 对于这种最大值最小类的问题,很自然的可以想到二分答案.很不幸 ...

  4. BZOJ 3669: [Noi2014]魔法森林( LCT )

    排序搞掉一维, 然后就用LCT维护加边MST. O(NlogN) ------------------------------------------------------------------- ...

  5. bzoj 3669: [Noi2014]魔法森林 (LCT)

    链接:https://www.lydsy.com/JudgeOnline/problem.php?id=3669 题面: 3669: [Noi2014]魔法森林 Time Limit: 30 Sec  ...

  6. [NOI2014]魔法森林 LCT

    题面 [NOI2014]魔法森林 题解 一条路径的代价为路径上的\(max(a[i]) + max(b[i])\),因为一条边同时有$a[i], b[i]$2种权值,直接处理不好同时兼顾到,所以我们考 ...

  7. bzoj3669: [Noi2014]魔法森林 lct版

    先上题目 bzoj3669: [Noi2014]魔法森林 这道题首先每一条边都有一个a,b 我们按a从小到大排序 每次将一条路劲入队 当然这道题权在边上 所以我们将边化为点去连接他的两个端点 当然某两 ...

  8. loj2245 [NOI2014]魔法森林 LCT

    [NOI2014]魔法森林 链接 loj 思路 a排序,b做动态最小生成树. 把边拆成点就可以了. uoj98.也许lct复杂度写假了..越卡常,越慢 代码 #include <bits/std ...

  9. bzoj 3669: [Noi2014] 魔法森林 LCT版

    Description 为了得到书法大家的真传,小E同学下定决心去拜访住在魔法森林中的隐士.魔法森林可以被看成一个包含个N节点M条边的无向图,节点标号为1..N,边标号为1..M.初始时小E同学在号节 ...

随机推荐

  1. typedef用法小结

    typedef用法小结- - 注意:本文转自网络,版权归原作者所有. typedef typedef用法小结- - 这两天在看程序的时候,发现很多地方都用到typedef,在结构体定义,还有一些数组等 ...

  2. 【动态规划】天堂(Heaven) 解题报告

    天堂(heaven) 题目描述 每一个要上天堂的人都要经历一番考验,当然包括小X,小X开始了他进入天堂的奇异之旅.地狱有18层,天堂竟然和地狱一样,也有很多很多层,天堂共有N层.从下到上依次是第1,2 ...

  3. Redis教程01——命令

    APPEND key value追加一个值到key上 AUTH password验证服务器 BGREWRITEAOF 异步重写追加文件 BGSAVE 异步保存数据集到磁盘上 BITCOUNT key ...

  4. poj 3169 Layout

    Layout Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 8610   Accepted: 4147 Descriptio ...

  5. hdu 2066 一个人的旅行(最短路问题)

    最短路································· 类似的问题还有好多不会!慢慢学吧!!!!. 进步,哪怕每天一点也行! (恋爱不是小事,确实小事的积累!(听着酷狗音乐台说的,很 ...

  6. 工厂模式 - 程序实现(java)

    09年5月CSDN一网友提出如下问题: 设计一个用于管理银行客户的类BankCustomer: 仅描述客户的几个重要方面: 帐号.身份证号.姓名.联系方式.密码.账户余额. 所有的成员变量均用priv ...

  7. MySql The service could not be started

    MySql安装 由于需要用mySql数据库今天就把它安上了,每次安装软件,数据库总是够我们折腾的,有时出现错误甚至比重装系统还要让人头疼. 今天在安的过程中就不出了很多错误,在重启与重装的反复捣鼓中终 ...

  8. Hadoop平台提供离线数据和Storm平台提供实时数据流

    1.准备工作 2.一个Storm集群的基本组件 3.Topologies 4.Stream 5.数据模型(Data Model) 6.一个简单的Topology 7.流分组策略(Stream grou ...

  9. java Map实现的cache manager

    一个模仿memcached的JAVA虚拟缓存工具,可以缓存java对象 import java.io.ByteArrayInputStream; import java.io.ByteArrayOut ...

  10. Java语言基础(五)

    Java语言基础(五) 一.浮点数 浮点数就是小数,其标准是IEEE 754,用指数和尾数表示 例如30000=3*10000=3*10^4  其中4是指数,3是尾数 Java中,浮点数有float ...