洛谷P2387 [NOI2014]魔法森林(LCT)
在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)的更多相关文章
- 洛谷P2387 [NOI2014]魔法森林(LCT)
魔法森林 题目传送门 解题思路 把每条路按照\(a\)的值从小到大排序.然后用LCT按照b的值维护最小生成树,将边按照顺序放入.如果\(1\)到\(n\)有了一条路径,就更新最小答案.这个过程就相当于 ...
- 洛谷 P2387 [NOI2014]魔法森林 解题报告
P2387 [NOI2014]魔法森林 题目描述 为了得到书法大家的真传,小 E 同学下定决心去拜访住在魔法森林中的隐 士.魔法森林可以被看成一个包含 n 个节点 m 条边的无向图,节点标号为 1,2 ...
- 洛谷P2387 [NOI2014]魔法森林(lct维护最小生成树)
题目描述 为了得到书法大家的真传,小 E 同学下定决心去拜访住在魔法森林中的隐 士.魔法森林可以被看成一个包含 n 个节点 m 条边的无向图,节点标号为 1,2,3,…,n,边标号为 1,2,3,…, ...
- 洛谷P2387 [NOI2014]魔法森林(LCT,Splay)
在XZY&XZZ巨佬的引领下,一枚蒟蒻终于啃动了这道题...... 这次还是第一次写LCT维护边权,还要化边为点,思路乱七八糟的,写起来也不顺手,还好调了许久终于AC啦. 贪心排序按一个关键字 ...
- 洛谷 2387 NOI2014魔法森林 LCT
[题解] 我们先把边按照$a$值从小到大排序,并按照这个顺序加边. 如果当前要加入的边连接的两点$u$与$v$已经是连通的,那么直接加入这条边就会出现环.这时我们需要删除这个环中$b$值最大的边.因此 ...
- P2387 [NOI2014]魔法森林 LCT维护最小生成树
\(\color{#0066ff}{ 题目描述 }\) 为了得到书法大家的真传,小 E 同学下定决心去拜访住在魔法森林中的隐 士.魔法森林可以被看成一个包含 n 个节点 m 条边的无向图,节点标号为 ...
- 洛谷2387 NOI2014魔法森林(LCT维护最小生成树)
本题是运用LCT来维护一个最小生成树. 是一个经典的套路 题目中求的是一个\(max(a_i)+max(b_i)\)尽可能小的路径. 那么这种的一个套路就是,先按照一维来排序,然后用LCT维护另一维 ...
- [Luogu P2387] [NOI2014]魔法森林 (LCT维护边权)
题面 传送门:https://www.luogu.org/problemnew/show/P2387 Solution 这题的思想挺好的. 对于这种最大值最小类的问题,很自然的可以想到二分答案.很不幸 ...
- 【洛谷P2387】魔法森林
题目大意:给定一个 N 个点,M 条边的无向图,边有两个边权 a, b,求从 1 号节点到 N 号节点路径的两个权值和的最大值最小是多少. 题解: 对于有两个属性的结构的最优化问题,可以考虑先按照其中 ...
随机推荐
- Ubuntu下搭建Ruby On Rails
Ruby on Rails是一个非常高效的Web应用程序框架由David Heinemeier Hansson使用Ruby语言编写. 这是一个开源 Ruby 框架,用于开发数据库支持的Web应用程序. ...
- lucas定理的证明
http://baike.baidu.com/link?url=jJgkOWPSRMobN7Zk4kIrQAri8m0APxcxP9d-C6qSkIuembQekeRwUoEoBd6bwdidmoCR ...
- 20155216 Exp8 WEB基础实践
Exp8 WEB基础实践 实践内容 Apache环境配置 apache是kali下的web服务器,通过访问 ip地址+端口号+文件名称 打开对应的网页. 输入命令 vi /etc/apache2/po ...
- Linux每天一个命令:cat
Linux cat命令 命令:cat cat 命令用于连接文件并打印到标准输出设备上. 使用权限 所有使用者 语法格式 cat [-AbeEnstTuv] [--help] [--version] f ...
- 一道面试题来了解线程notifyAll()和wait()的方法
题目:三个线程,分别打印A.B.C,要求按ABC的顺序循环打印10次. package com.slowcity.crud.controller; public class PrintOneTwoTh ...
- C语言中指针占据内存空间问题
以前一直有个疑问,指向不同类型的指针到底占用的内存空间是多大呢? 这个问题我多次问过老师,老师的答案是"指向不同类型的指针占据的内存空间大小不同",我一直很之一这个答案,今天我就做 ...
- Visual Studio控制台程序输出窗口一闪而过的解决方法
转载大牛的博客,自己也遇到了类似的问题,解决方法很详细,也很管用 刚接触 Visual Studio的时候大多数人会写个Hello World的程序试一下,有的人会发现执行结束后输出窗口会一闪而过 ...
- Microsoft Dynamics CRM 增删改子表汇总子表的某个字段到主表的某个字段(通用插件)
背景 经常有某个汇总子表的数量到主表的总数量,或者汇总子表的总价到主表的总价这种需求. 传统的做法: 1.就是为每个子表实体单独写成一个插件,但是这样不好复用. 2.主表的汇总字段是汇总货币类型,但是 ...
- 用opencv实现工控机的开机录像
需要训练一个神经网络模型,可能需要用到很多视频数据,所以我想把手头的工控机设置为上电自启动,再借助opencv编译一个可执行文件,放在windows开机启动文件夹里,这样只要连接好摄像头和工控机以及电 ...
- Scrapy的日志等级和请求传参
日志等级 日志信息: 使用命令:scrapy crawl 爬虫文件 运行程序时,在终端输出的就是日志信息: 日志信息的种类: ERROR:一般错误: WARNING:警告: INFO:一般的信息: ...