「NOI2014」 魔法森林 - 动态树LCT

2024-01-02 07:48
文章标签 动态 森林 魔法 lct noi2014

本文主要是介绍「NOI2014」 魔法森林 - 动态树LCT,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

题目描述

为了得到书法大家的真传,小E同学下定决心去拜访住在魔法森林中的隐士。魔法森林可以被看成一个包含个 N N N节点 M M M条边的无向图,节点标号为 1 ⋯ N 1\cdots N 1N,边标号为 1 ⋯ M 1\cdots M 1M。初始时小E同学在号节点 1 1 1,隐士则住在号节点 N N N。小E需要通过这一片魔法森林,才能够拜访到隐士。

魔法森林中居住了一些妖怪。每当有人经过一条边的时候,这条边上的妖怪就会对其发起攻击。幸运的是,在号节点住着两种守护精灵: A A A型守护精灵与 B B B型守护精灵。小E可以借助它们的力量,达到自己的目的。

只要小E带上足够多的守护精灵,妖怪们就不会发起攻击了。具体来说,无向图中的每一条边 E i E_i Ei包含两个权值 A i A_i Ai B i B_i Bi。若身上携带的 A A A型守护精灵个数不少于 A i A_i Ai,且 B B B型守护精灵个数不少于 B i B_i Bi,这条边上的妖怪就不会对通过这条边的人发起攻击。当且仅当通过这片魔法森林的过程中没有任意一条边的妖怪向小E发起攻击,他才能成功找到隐士。

由于携带守护精灵是一件非常麻烦的事,小E想要知道,要能够成功拜访到隐士,最少需要携带守护精灵的总个数。守护精灵的总个数为 A A A型守护精灵的个数与 B B B型守护精灵的个数之和。

输入格式

第1行包含两个整数 N , M N,M N,M,表示无向图共有 N N N个节点, M M M条边。 接下来 M M M行,第行包含 4 4 4个正整数 X i , Y i , A i , B i Xi_,Y_i,A_i,B_i Xi,Yi,Ai,Bi,描述第 i i i条无向边。其中 X i X_i Xi Y i Y_i Yi为该边两个端点的标号, A i A_i Ai B i B_i Bi的含义如题所述。 注意数据中可能包含重边与自环。

输出格式

输出一行一个整数:如果小E可以成功拜访到隐士,输出小E最少需要携带的守护精灵的总个数;如果无论如何小E都无法拜访到隐士,输出-1

分析

如果没有 B B B型守护精灵,那么就是求 1 1 1~ N N N的所有路径中最大边权的最小值。很容易想到用最小生成树解决。现在一条边有两个权值,同样按照Kruskal算法的思路,固定边的一种权值 A i A_i Ai,将其按从小到大排序,然后就可以发现,答案中 B i B_i Bi就一定在以 B i B_i Bi为权值的最小生成树上,于是就可以用LCT维护 B B B的最小生成树。当 1 1 1 N N N连通时就更新答案。对于自环与重边,可以不处理,LCT会自动过滤。似乎还有一种用Spfa的方法,供大家思考。 (LCT也没那么长,压行后百行都不到)

代码

#include <algorithm>
#include <climits>
#include <cstdio>
using namespace std;
const int N=500005,M=100005;
const int V=N+M,INF=INT_MAX>>1;
typedef long long LL;
struct Edge {int u,v,ca,cb;}e[M];
int n,m,fa[N],ans;
bool cmp(Edge a,Edge b) {return a.ca<b.ca;}
int getf(int x) {return fa[x]==x?x:fa[x]=getf(fa[x]);}
int c[V][2],f[V];
int mx[V],v[V],rv[V],st[V];
void init(int x,int p) {mx[x]=v[x]=p;}
bool nroot(int x) {return c[f[x]][0]==x||c[f[x]][1]==x;}
void makerv(int x) {rv[x]^=1;swap(c[x][0],c[x][1]);}
void pushup(int x) {mx[x]=v[x];if (e[mx[c[x][0]]].cb>e[mx[x]].cb) mx[x]=mx[c[x][0]];if (e[mx[c[x][1]]].cb>e[mx[x]].cb) mx[x]=mx[c[x][1]];
}
void pushdown(int x) {if (!x||!rv[x]) return;if (c[x][0]) makerv(c[x][0]);if (c[x][1]) makerv(c[x][1]);rv[x]=0;
}
void pushtg(int x) {int top=0;st[++top]=x;while (f[x]) st[++top]=(x=f[x]);while (top) pushdown(st[top--]);
}
void rotate(int x) {int y=f[x],z=f[y];int k=c[y][1]==x;if (nroot(y)) c[z][c[z][1]==y]=x;f[x]=z;f[y]=x;if (c[x][k^1]) f[c[x][k^1]]=y;c[y][k]=c[x][k^1];c[x][k^1]=y;pushup(y);pushup(x);
}
void splay(int x) {pushtg(x);for (int y,z;y=f[x],z=f[y],nroot(x);rotate(x))if (nroot(y)) rotate((c[y][0]==x)^(c[z][0]==y)?x:y);pushup(x);
}
void access(int x) {for (int y=0;x;splay(x),c[x][1]=y,pushup(x),x=f[y=x]);}
void makert(int x) {access(x);splay(x);makerv(x);}
void split(int x,int y) {makert(x);access(y);splay(y);}
void link(int x,int y) {makert(x);f[x]=y;pushup(y);}
void cut(int x,int y) {split(x,y);f[x]=c[y][0]=0;pushup(y);}
int main() {scanf("%d%d",&n,&m);for (int i=1;i<=m;i++) {int u,v,a,b;scanf("%d%d%d%d",&u,&v,&a,&b);e[i]=(Edge){u,v,a,b};}sort(e+1,e+m+1,cmp);for (int i=1;i<=n;i++) init(i,0),fa[i]=i;for (int i=n+1;i<=n+m;i++) init(i,i-n);ans=INF;for (int i=1;i<=m;i++) {int u=e[i].u,v=e[i].v;int fu=getf(u),fv=getf(v);if (fu!=fv) link(u,i+n),link(i+n,v),fa[fu]=fv;else {split(u,v);int num=mx[v];if (e[num].cb>e[i].cb) {cut(e[num].u,num+n);cut(num+n,e[num].v);link(u,i+n);link(i+n,v);}}if (getf(1)==getf(n)) {split(1,n);ans=min(ans,e[i].ca+e[mx[n]].cb);}}if (ans==INF) printf("-1");else printf("%d",ans);return 0;
}

这篇关于「NOI2014」 魔法森林 - 动态树LCT的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/561784

相关文章

Java调用C#动态库的三种方法详解

《Java调用C#动态库的三种方法详解》在这个多语言编程的时代,Java和C#就像两位才华横溢的舞者,各自在不同的舞台上展现着独特的魅力,然而,当它们携手合作时,又会碰撞出怎样绚丽的火花呢?今天,我们... 目录方法1:C++/CLI搭建桥梁——Java ↔ C# 的“翻译官”步骤1:创建C#类库(.NET

MyBatis编写嵌套子查询的动态SQL实践详解

《MyBatis编写嵌套子查询的动态SQL实践详解》在Java生态中,MyBatis作为一款优秀的ORM框架,广泛应用于数据库操作,本文将深入探讨如何在MyBatis中编写嵌套子查询的动态SQL,并结... 目录一、Myhttp://www.chinasem.cnBATis动态SQL的核心优势1. 灵活性与可

Mybatis嵌套子查询动态SQL编写实践

《Mybatis嵌套子查询动态SQL编写实践》:本文主要介绍Mybatis嵌套子查询动态SQL编写方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录前言一、实体类1、主类2、子类二、Mapper三、XML四、详解总结前言MyBATis的xml文件编写动态SQL

SpringBoot实现Kafka动态反序列化的完整代码

《SpringBoot实现Kafka动态反序列化的完整代码》在分布式系统中,Kafka作为高吞吐量的消息队列,常常需要处理来自不同主题(Topic)的异构数据,不同的业务场景可能要求对同一消费者组内的... 目录引言一、问题背景1.1 动态反序列化的需求1.2 常见问题二、动态反序列化的核心方案2.1 ht

golang实现动态路由的项目实践

《golang实现动态路由的项目实践》本文主要介绍了golang实现动态路由项目实践,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习... 目录一、动态路由1.结构体(数据库的定义)2.预加载preload3.添加关联的方法一、动态路由1

Python Selenium动态渲染页面和抓取的使用指南

《PythonSelenium动态渲染页面和抓取的使用指南》在Web数据采集领域,动态渲染页面已成为现代网站的主流形式,本文将从技术原理,环境配置,核心功能系统讲解Selenium在Python动态... 目录一、Selenium技术架构解析二、环境搭建与基础配置1. 组件安装2. 驱动配置3. 基础操作模

慢sql提前分析预警和动态sql替换-Mybatis-SQL

《慢sql提前分析预警和动态sql替换-Mybatis-SQL》为防止慢SQL问题而开发的MyBatis组件,该组件能够在开发、测试阶段自动分析SQL语句,并在出现慢SQL问题时通过Ducc配置实现动... 目录背景解决思路开源方案调研设计方案详细设计使用方法1、引入依赖jar包2、配置组件XML3、核心配

springboot使用Scheduling实现动态增删启停定时任务教程

《springboot使用Scheduling实现动态增删启停定时任务教程》:本文主要介绍springboot使用Scheduling实现动态增删启停定时任务教程,具有很好的参考价值,希望对大家有... 目录1、配置定时任务需要的线程池2、创建ScheduledFuture的包装类3、注册定时任务,增加、删

SpringBoot基于配置实现短信服务策略的动态切换

《SpringBoot基于配置实现短信服务策略的动态切换》这篇文章主要为大家详细介绍了SpringBoot在接入多个短信服务商(如阿里云、腾讯云、华为云)后,如何根据配置或环境切换使用不同的服务商,需... 目录目标功能示例配置(application.yml)配置类绑定短信发送策略接口示例:阿里云 & 腾

MySQL中动态生成SQL语句去掉所有字段的空格的操作方法

《MySQL中动态生成SQL语句去掉所有字段的空格的操作方法》在数据库管理过程中,我们常常会遇到需要对表中字段进行清洗和整理的情况,本文将详细介绍如何在MySQL中动态生成SQL语句来去掉所有字段的空... 目录在mysql中动态生成SQL语句去掉所有字段的空格准备工作原理分析动态生成SQL语句在MySQL