在XZY&XZZ巨佬的引领下,一枚蒟蒻终于啃动了这道题。。。。。。

这次还是第一次写LCT维护边权,还要化边为点,思路乱七八糟的,写起来也不顺手,还好调了许久终于AC啦。

贪心排序按一个关键字从小到大枚举边,维护另一个关键字的最小生成树,这样的思路真是太巧妙啦。(然而没有题解的滋养我什么也干不了)

只是关于写法上面,我又有些和Dalao们不一样的地方(因为是自己乱写的)。

link和cut好像脱离了传统意义,本蒟蒻用了link(x)表示将编号为x的边加入用LCT维护的最小生成树,cut(x)反之。

link其实是要连两次,因为要严格深度递增,就让边的一个端点的父亲指向这个代表边的点(轻边),再让代表边的点的父亲指向边的另一个端点(还是轻边)。当然啦,深度大的那个点要先makeroot,不然会影响正确性。

cut就是断两次了,把代表边的点下面那个点(深度大的)access,splay(代表边的点),此时两个端点一个深度小,在左边,一个深度大,在右边,左右儿子全断掉就OK。

其实常规link,cut没问题啊,我也不知道什么时候脑袋短路搞出这种不成熟的写法,不过稍微算算,实际操作量少了些,比起两遍link或cut常数会小一点。

update:这种link和cut可能存在问题。。。还是要写两遍(不知道当时怎么过的)

不过说到常数又留下一个败笔——这一题较特殊,维护连通性可以用并查集,避免了大量findroot(虽然不会T而已)。只是我没有写。findroot真慢呀!以后还是要记住这个小细节。

代码还是放一下

#include<cstdio>
#include<cstdlib>
#include<algorithm>
using namespace std;
#define R register int
#define I inline void
#define lc c[x][0]
#define rc c[x][1]
#define G ch=getchar()
#define min2(x,y) if(x>y)x=y;
const int N=200000,P=131072;
//P是用来区分点和边的,边的编号在LCT中不变,点的编号全部加上P(为压常用了这样一个数,加上位或运算)
int f[N],c[N][2],mx[N];
bool r[N];
I in(R&z){
register char G;
while(ch<'-')G;
z=ch&15;G;
while(ch>'-')z*=10,z+=ch&15,G;
}
struct EDGE{
int u,v,a,b;
inline bool operator<(EDGE x)const{
return a<x.a;
}
I read(){
in(u);in(v);in(a);in(b);
u|=P;v|=P;//编号变化
}
}e[N];//边放进结构体
inline bool nroot(R x){
return c[f[x]][0]==x||c[f[x]][1]==x;
}
I pushup(R x){
mx[x]=x;
if(e[mx[x]].b<e[mx[lc]].b)mx[x]=mx[lc];
if(e[mx[x]].b<e[mx[rc]].b)mx[x]=mx[rc];//三种情况都要看
}
I pushdown(R x){
if(r[x]){
R t=lc;lc=rc;rc=t;
r[lc]^=1;r[rc]^=1;r[x]=0;
}
}
I pushall(R x){//懒得手写栈,直接用函数堆栈(逃
if(nroot(x))pushall(f[x]);
pushdown(x);
}
I rotate(R x){
R y=f[x],z=f[y],k=c[y][1]==x,w=c[x][!k];
if(nroot(y))c[z][c[z][1]==y]=x;c[x][!k]=y;c[y][k]=w;
f[w]=y;f[y]=x;f[x]=z;
pushup(y);
}
I splay(R x){
R y=x;
pushall(x);
while(nroot(x)){
if(nroot(y=f[x]))
rotate((c[y][0]==x)^(c[f[y]][0]==y)?x:y);
rotate(x);
}
pushup(x);
}
I access(R x){
for(R y=0;x;x=f[y=x])
splay(x),rc=y,pushup(x);
}
I mroot(R x){
access(x);splay(x);
r[x]^=1;
}
inline int froot(R x){
access(x);splay(x);
while(lc)x=lc;
return x;
}
I link(R x){
R y=e[x].u,z=e[x].v;
mroot(z);
f[f[z]=x]=y;
}//非正常link与cut
I cut(R x){
access(e[x].v);splay(x);
lc=rc=f[lc]=f[rc]=0;
pushup(x);
}
int main(){
R n,m,i,y,z,ans=999999;//ans给极大值
in(n);in(m);
for(i=1;i<=m;++i)e[i].read();
sort(e+1,e+m+1);
for(i=1;i<=m;++i)
{
if((y=e[i].u)==(z=e[i].v))continue;
mroot(y);
if(y!=froot(z))link(i);//不联通,直接连
else if(e[i].b<e[mx[z]].b)cut(mx[z]),link(i);//联通,但有更小的边替换
mroot(1|P);
if((1|P)==froot(n|P))min2(ans,e[i].a+e[mx[n|P]].b);//1与n联通就更新答案
}
printf("%d\n",ans==999999?-1:ans);
return 0;
}

洛谷P2387 [NOI2014]魔法森林(LCT,Splay)的更多相关文章

  1. 洛谷P2387 [NOI2014]魔法森林(LCT)

    魔法森林 题目传送门 解题思路 把每条路按照\(a\)的值从小到大排序.然后用LCT按照b的值维护最小生成树,将边按照顺序放入.如果\(1\)到\(n\)有了一条路径,就更新最小答案.这个过程就相当于 ...

  2. 洛谷 P2387 [NOI2014]魔法森林 解题报告

    P2387 [NOI2014]魔法森林 题目描述 为了得到书法大家的真传,小 E 同学下定决心去拜访住在魔法森林中的隐 士.魔法森林可以被看成一个包含 n 个节点 m 条边的无向图,节点标号为 1,2 ...

  3. 洛谷P2387 [NOI2014]魔法森林(lct维护最小生成树)

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

  4. 洛谷P2387 [NOI2014]魔法森林(LCT)

    在XZY&XZZ巨佬的引领下,一枚蒟蒻终于啃动了这道题...... 这次还是第一次写LCT维护边权,还要化边为点,思路乱七八糟的,写起来也不顺手,还好调了许久终于AC啦. 贪心排序按一个关键字 ...

  5. 洛谷 2387 NOI2014魔法森林 LCT

    [题解] 我们先把边按照$a$值从小到大排序,并按照这个顺序加边. 如果当前要加入的边连接的两点$u$与$v$已经是连通的,那么直接加入这条边就会出现环.这时我们需要删除这个环中$b$值最大的边.因此 ...

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

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

  7. 洛谷2387 NOI2014魔法森林(LCT维护最小生成树)

    本题是运用LCT来维护一个最小生成树. 是一个经典的套路 题目中求的是一个\(max(a_i)+max(b_i)\)尽可能小的路径. 那么这种的一个套路就是,先按照一维来排序,然后用LCT维护另一维 ...

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

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

  9. 【洛谷P2387】魔法森林

    题目大意:给定一个 N 个点,M 条边的无向图,边有两个边权 a, b,求从 1 号节点到 N 号节点路径的两个权值和的最大值最小是多少. 题解: 对于有两个属性的结构的最优化问题,可以考虑先按照其中 ...

随机推荐

  1. 简单的led驱动程序设计

    基于ok6410: led驱动程序: vim led.c #include<linux/kernel.h>#include<linux/module.h>#include< ...

  2. html中meta标签及用法理解

    自己一直想成为高级前端开发工程师,而自学.奈何最近感觉自学收效甚微,一度迷茫. 不破不立,打算改变这样的状态. 春节后上班第一天,今年打算好好实现自己的前端梦想. 重新整理.总结前端技术. 废话,就不 ...

  3. 【Tools】ubuntu16.04升级Python2.7到3.5

    最近开始学Python,但我发现我ubuntu16.04上默认的Python是2.7,并不是3,x 于是准备Python升级,记录安装过程给初学者参考一下. 1.先取得管理员权限, 个人习惯先取得管理 ...

  4. CocosCreator游戏开发---菜鸟学习之路(三)如何在CocosCreator中使用Pomelo

    PS(废话): 这段时间都在研究网易的Pomelo框架,作为新手小白,自然遇到了不少坑爹的事情.(当然也有可能是因为自己技术不过关的原因所以导致在很多基础的问题上纠结了很久.)网上也搜索了好久,但是基 ...

  5. centos7安装部署gitlab服务器

    [gitlab需要内存至少4GB]   我这里使用的是centos 7 64bit,我试过centos 6也是可以的! 1. 安装依赖软件 yum -y install policycoreutils ...

  6. jq自定义多选下拉列表框

    多选选择国家插件 https://gitee.com/richard1015/dropDownList

  7. HttpClient读取数据乱码的解决方案

    博主是一个近十年的老书虫了,从高中那会儿就开始看网络小说.每天半天看晚上看啊,终于眼睛也近视了,成绩也下降了(....好像说远了) 最近在追辰东的<圣墟>,最近写到精彩部分了,一直等更新. ...

  8. Java数字签名——DSA算法

    RSA数字加密算法参考:http://www.cnblogs.com/LexMoon/p/javaRSA.html DSS: 数字签名标准 DSA: 数字签名算法 DSA仅仅包含数字签名 —————— ...

  9. 剑指offer随练

    合并两个排序的链表 题目描述 输入两个单调递增的链表,输出两个链表合成后的链表,当然我们需要合成后的链表满足单调不减规则. 思路:使用递归的方法,合并头节点,然后对剩下的链表接着合并头节点,直到合并完 ...

  10. 情景linux—不曾了解的cat用法

    情景 cat是linux命令中最为基础的命令之一,它是"concatenate"(连接)的简写,作用概述是concatenate and print files,即:连接和查看文件 ...