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同学在号节 ...
随机推荐
- Google Map API 学习五
今天其实收货很大的 1.InfoWindow google.maps.InfoWindow class An overlay that looks like a bubble and is often ...
- 4种字符串匹配算法:KMP(下)
回顾:4种字符串匹配算法:BS朴素 Rabin-karp(上) 4种字符串匹配算法:有限自动机(中) 1.图解 KMP算法是一种改进的字符串匹配算法,由D.E.Knuth,J.H.Morris和V.R ...
- Java 集合框架 ArrayList 源码剖析
总体介绍 ArrayList实现了List接口,是顺序容器,即元素存放的数据与放进去的顺序相同,允许放入null元素,底层通过数组实现.除该类未实现同步外,其余跟Vector大致相同.每个ArrayL ...
- [置顶] c# asp.net 修改webconfig文件 配置
c# asp.net 修改webconfig文件 配置 #region 修改config文件 /// <summary> /// 修改config文件(AppSetting节点) /// ...
- MediaInfo源代码分析 3:Open()函数
我们来看一下MediaInfo中的Open()函数的内部调用过程 首先open函数封装了MediaInfo_Internal类中的open()函数 //打开文件 size_t MediaInfo::O ...
- maven常用插件配置
1.maven-jar-plugin插件 <!-- 排除资源文件中的properties文件,不需要打到jar中,后面通过assembly插件打包到conf目录中 --><plugi ...
- mysql中group_concat函数用法
该函数返回带有来自一个组的连接的非NULL值的字符串结果.该函数是一个增强的Sybase SQL Anywhere支持的基本LIST()函数. 语法结构: GROUP_CONCAT([DISTINCT ...
- 最新Connectify注冊码(序列号) Connectify3.7序列号 破解版
Connectify序列号.最新注冊码 今天给大家公布一个Connectify最新版的序列号(注冊码) 今天给大家公布一个Connectify最新版的序列号(注冊码) 经本人測试该注冊码为最新版Con ...
- C. Tourist Problem
http://codeforces.com/problemset/problem/340/C 赛时没想出赛后却能较快想出深深的教育自己做题一定要静下心来,不要轻易放弃,认真思考,不要浮躁着急,不要太容 ...
- android 28 SimpleAdapter
监听器返回fasle,则事件还会分发给其他监听器. SimpleAdapter是BaseAdapter的子类,对适配器进行了简化,数据的格式是List,List的元素必须是Map, public Si ...