Vijos1865 NOI2014 魔法森林 LCT维护生成树
基本思路:
首先按照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维护生成树的更多相关文章
- P2387 [NOI2014]魔法森林 LCT维护最小生成树
\(\color{#0066ff}{ 题目描述 }\) 为了得到书法大家的真传,小 E 同学下定决心去拜访住在魔法森林中的隐 士.魔法森林可以被看成一个包含 n 个节点 m 条边的无向图,节点标号为 ...
- 【BZOJ 3669】 [Noi2014]魔法森林 LCT维护动态最小生成树
这道题看题意是在求一个二维最小瓶颈路,唯一可行方案就是枚举一维在这一维满足的条件下使另一维最小,那么我们就把第一维排序利用A小的边在A大的情况下仍成立来动态加边维护最小生成树. #include &l ...
- [Luogu P2387] [NOI2014]魔法森林 (LCT维护边权)
题面 传送门:https://www.luogu.org/problemnew/show/P2387 Solution 这题的思想挺好的. 对于这种最大值最小类的问题,很自然的可以想到二分答案.很不幸 ...
- BZOJ 3669: [Noi2014]魔法森林( LCT )
排序搞掉一维, 然后就用LCT维护加边MST. O(NlogN) ------------------------------------------------------------------- ...
- bzoj 3669: [Noi2014]魔法森林 (LCT)
链接:https://www.lydsy.com/JudgeOnline/problem.php?id=3669 题面: 3669: [Noi2014]魔法森林 Time Limit: 30 Sec ...
- [NOI2014]魔法森林 LCT
题面 [NOI2014]魔法森林 题解 一条路径的代价为路径上的\(max(a[i]) + max(b[i])\),因为一条边同时有$a[i], b[i]$2种权值,直接处理不好同时兼顾到,所以我们考 ...
- bzoj3669: [Noi2014]魔法森林 lct版
先上题目 bzoj3669: [Noi2014]魔法森林 这道题首先每一条边都有一个a,b 我们按a从小到大排序 每次将一条路劲入队 当然这道题权在边上 所以我们将边化为点去连接他的两个端点 当然某两 ...
- loj2245 [NOI2014]魔法森林 LCT
[NOI2014]魔法森林 链接 loj 思路 a排序,b做动态最小生成树. 把边拆成点就可以了. uoj98.也许lct复杂度写假了..越卡常,越慢 代码 #include <bits/std ...
- bzoj 3669: [Noi2014] 魔法森林 LCT版
Description 为了得到书法大家的真传,小E同学下定决心去拜访住在魔法森林中的隐士.魔法森林可以被看成一个包含个N节点M条边的无向图,节点标号为1..N,边标号为1..M.初始时小E同学在号节 ...
随机推荐
- typedef用法小结
typedef用法小结- - 注意:本文转自网络,版权归原作者所有. typedef typedef用法小结- - 这两天在看程序的时候,发现很多地方都用到typedef,在结构体定义,还有一些数组等 ...
- 【动态规划】天堂(Heaven) 解题报告
天堂(heaven) 题目描述 每一个要上天堂的人都要经历一番考验,当然包括小X,小X开始了他进入天堂的奇异之旅.地狱有18层,天堂竟然和地狱一样,也有很多很多层,天堂共有N层.从下到上依次是第1,2 ...
- Redis教程01——命令
APPEND key value追加一个值到key上 AUTH password验证服务器 BGREWRITEAOF 异步重写追加文件 BGSAVE 异步保存数据集到磁盘上 BITCOUNT key ...
- poj 3169 Layout
Layout Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 8610 Accepted: 4147 Descriptio ...
- hdu 2066 一个人的旅行(最短路问题)
最短路································· 类似的问题还有好多不会!慢慢学吧!!!!. 进步,哪怕每天一点也行! (恋爱不是小事,确实小事的积累!(听着酷狗音乐台说的,很 ...
- 工厂模式 - 程序实现(java)
09年5月CSDN一网友提出如下问题: 设计一个用于管理银行客户的类BankCustomer: 仅描述客户的几个重要方面: 帐号.身份证号.姓名.联系方式.密码.账户余额. 所有的成员变量均用priv ...
- MySql The service could not be started
MySql安装 由于需要用mySql数据库今天就把它安上了,每次安装软件,数据库总是够我们折腾的,有时出现错误甚至比重装系统还要让人头疼. 今天在安的过程中就不出了很多错误,在重启与重装的反复捣鼓中终 ...
- Hadoop平台提供离线数据和Storm平台提供实时数据流
1.准备工作 2.一个Storm集群的基本组件 3.Topologies 4.Stream 5.数据模型(Data Model) 6.一个简单的Topology 7.流分组策略(Stream grou ...
- java Map实现的cache manager
一个模仿memcached的JAVA虚拟缓存工具,可以缓存java对象 import java.io.ByteArrayInputStream; import java.io.ByteArrayOut ...
- Java语言基础(五)
Java语言基础(五) 一.浮点数 浮点数就是小数,其标准是IEEE 754,用指数和尾数表示 例如30000=3*10000=3*10^4 其中4是指数,3是尾数 Java中,浮点数有float ...