【NOI2014】 魔法森林---解题报告
传送门
题目大意
给定 \(n\) 个点和 \(m\) 条边。每条边包含起点终点和两个精灵的最低限制,求最少需要携带的精灵数量。
题目解析
直接套 LCT 板子
将所有边按照进行升序排序,从小到大将边加入,在已经加入边的图上找路径的最大值,求出最大值和当前枚举的和用于更新全局的最小值答案。
为什么呢?因为要 \(a\),\(b\) 都满足才能通过某条边,所以结果必定为某条边的 \(a_i\) 或 \(b_i\), 因此可以固定 \(a\) 的信息来降低复杂度。即每次选取小于等于 \(a_i\) 大小的边去维护一条 \(1\) 到 \(n\) 的路径.
动态加边,维护最大值。
直接套 LCT 板子!!
虽然题目给出的是一张图, 但实际上只需要维护出一条从 \(1\) 到 \(n\) 的路径即可.因此当新加入一条边会使维护的树变成图时, 就需要去找到环, 若新边比环中最大值小, 那么将环中的最大边删去, 加入新边即可。
然后要注意用并查集(好像是卡常,因为 yxc 直接用的并查集)
利用动态树的特性快速求路径上的最大点权值。最后注意一下删边时的编号映射。(关于我忘了切断子树卡了半天15pts艹)
代码实现
#include <bits/stdc++.h>
#define int long long
#define rint register int
#define endl '\n'
using namespace std;
const int N = 1e6 + 5;
int n, m, p[N], stk[N], ans = 0x3f3f3f3f;
struct Edge
{
int x, y, a, b;
bool operator<(const Edge &t) const { return a < t.a; }
} e[N];
struct node
{
int s[2], p, v, mx, rev;
} tr[N];
int inline min(int a, int b)
{
return a < b ? a : b;
}
int inline find(int x)
{
if (p[x] != x)
p[x] = find(p[x]);
return p[x];
}
void inline pushrev(int u)
{
swap(tr[u].s[0], tr[u].s[1]);
tr[u].rev ^= 1;
return;
}
void inline pushup(int u)
{
tr[u].mx = u;
int ll = tr[tr[u].s[0]].mx;
int rr = tr[tr[u].s[1]].mx;
if (tr[ll].v > tr[tr[u].mx].v)
{
tr[u].mx = ll;
}
if (tr[rr].v > tr[tr[u].mx].v)
{
tr[u].mx = rr;
}
return;
}
void inline pushdown(int u)
{
if (tr[u].rev)
{
pushrev(tr[u].s[0]);
pushrev(tr[u].s[1]);
tr[u].rev = 0;
}
return;
}
bool inline isroot(int u)
{
return tr[tr[u].p].s[0] != u && tr[tr[u].p].s[1] != u;
}
void inline rotate(int x)
{
int y = tr[x].p;
int z = tr[y].p;
int k = tr[y].s[1] == x;
if (!isroot(y))
{
tr[z].s[tr[z].s[1] == y] = x;
}
tr[x].p = z;
tr[y].s[k] = tr[x].s[k ^ 1], tr[tr[x].s[k ^ 1]].p = y;
tr[x].s[k ^ 1] = y, tr[y].p = x;
pushup(y);
pushup(x);
return;
}
void inline splay(int x)
{
int top = 0, r = x;
stk[++top] = r;
while (!isroot(r))
{
stk[++top] = r = tr[r].p;
}
while (top)
{
pushdown(stk[top--]);
}
while (!isroot(x))
{
int y = tr[x].p, z = tr[y].p;
if (!isroot(y))
{
if ((tr[z].s[1] == y) ^ (tr[y].s[1] == x))
rotate(x);
else
rotate(y);
}
rotate(x);
}
return;
}
void inline access(int x)
{
int z = x;
for (rint y = 0; x; y = x, x = tr[y].p)
{
splay(x);
tr[x].s[1] = y, pushup(x);
}
splay(z);
return;
}
void inline makeroot(int x)
{
access(x);
pushrev(x);
return;
}
int inline findroot(int x)
{
access(x);
while (tr[x].s[0])
{
pushdown(x);
x = tr[x].s[0];
}
splay(x);
return x;
}
void inline split(int x, int y)
{
makeroot(x);
access(y);
return;
}
void inline link(int x, int y)
{
makeroot(x);
if (findroot(y) != x)
tr[x].p = y;
return;
}
void inline cut(int x, int y)
{
makeroot(x);
if (findroot(y) == x && tr[x].s[1] == y && !tr[y].s[0])
{
tr[y].p = tr[x].s[1] = 0;
pushup(x);
}
return;
}
signed main()
{
cin >> n >> m;
for (rint i = 1; i <= m; i++)
{
int x, y, a, b;
cin >> x >> y >> a >> b;
e[i] = {x, y, a, b};
}
sort(e + 1, e + 1 + m);
for (rint i = 1; i <= n + m; i++)
{
p[i] = i;
if (i > n)
tr[i].v = e[i - n].b;
tr[i].mx = i;
}
for (rint i = 1; i <= m; i++)
{
int x = e[i].x;
int y = e[i].y;
int a = e[i].a;
int b = e[i].b;
if (find(x) == find(y))
{
split(x, y);
int t = tr[y].mx;
if (tr[t].v > b)
{
cut(t, e[t - n].x);
cut(t, e[t - n].y);
link(i + n, x);
link(i + n, y);
}
}
else
{
p[find(x)] = find(y);
link(i + n, x);
link(i + n, y);
}
if (find(1) == find(n))
{
split(1, n);
ans = min(ans, a + tr[tr[n].mx].v);
}
}
if (ans != 0x3f3f3f3f)
{
cout << ans << endl;
return 0;
}
puts("-1");
return 0;
}
【NOI2014】 魔法森林---解题报告的更多相关文章
- 洛谷 P2387 [NOI2014]魔法森林 解题报告
P2387 [NOI2014]魔法森林 题目描述 为了得到书法大家的真传,小 E 同学下定决心去拜访住在魔法森林中的隐 士.魔法森林可以被看成一个包含 n 个节点 m 条边的无向图,节点标号为 1,2 ...
- NOI2014魔法森林题解报告
题目描述 为了得到书法大家的真传,小 E 同学下定决心去拜访住在魔法森林中的隐 士.魔法森林可以被看成一个包含 n 个节点 m 条边的无向图,节点标号为 1,2,3,-,n,边标号为 1,2,3,-, ...
- NOI2014 魔法森林
3669: [Noi2014]魔法森林 Time Limit: 30 Sec Memory Limit: 512 MBSubmit: 106 Solved: 62[Submit][Status] ...
- bzoj 3669: [Noi2014]魔法森林 动态树
3669: [Noi2014]魔法森林 Time Limit: 30 Sec Memory Limit: 512 MBSubmit: 363 Solved: 202[Submit][Status] ...
- BZOJ 3669: [Noi2014]魔法森林( LCT )
排序搞掉一维, 然后就用LCT维护加边MST. O(NlogN) ------------------------------------------------------------------- ...
- bzoj 3669: [Noi2014]魔法森林
bzoj 3669: [Noi2014]魔法森林 Description 为了得到书法大家的真传,小E同学下定决心去拜访住在魔法森林中的隐士.魔法森林可以被看成一个包含个N节点M条边的无向图,节点标号 ...
- BZOJ_3669_[Noi2014]魔法森林_LCT
BZOJ_3669_[Noi2014]魔法森林_LCT Description 为了得到书法大家的真传,小E同学下定决心去拜访住在魔法森林中的隐士.魔法森林可以被看成一个包含个N节点M条边的无向图,节 ...
- bzoj 3669: [Noi2014]魔法森林 (LCT)
链接:https://www.lydsy.com/JudgeOnline/problem.php?id=3669 题面: 3669: [Noi2014]魔法森林 Time Limit: 30 Sec ...
- 「luogu2387」[NOI2014] 魔法森林
「luogu2387」[NOI2014] 魔法森林 题目大意 \(n\) 个点 \(m\) 条边的无向图,每条边上有两个权值 \(a,b\),求从 \(1\) 节点到 \(n\) 节点 \(max\{ ...
- P2387 [NOI2014]魔法森林(LCT)
P2387 [NOI2014]魔法森林 LCT边权维护经典题 咋维护呢?边化为点,边权变点权. 本题中我们把边对关键字A进行排序,动态维护关键字B的最小生成树 加边后出现环咋办? splay维护最大边 ...
随机推荐
- 采用PCA算法&KMeans算法来实现用户对物品类别的喜好细分(菜篮子分析)(附带数据集下载)
实现该项目的流程如下 """ 项目:用户对物品类别的喜好细分(菜篮子分析) 主算法:PCA降维算法 KMeans算法 总思路 1.导包 2.获取数据 3.数据处理 5.特 ...
- Ceres简单应用-求解(Powell's Function)鲍威尔函数最小值
Ceres 求解 Powell's function 的最小化 \(\quad\)现在考虑一个稍微复杂一点的例子-鲍威尔函数的最小化. \(\quad{}\) \(x=[x_1,x_2,x_3,x_4 ...
- css美化
编辑网页文本 span标签:能让某几个字凸显出来结构:span{color:red:} <span>123<span> 字体样式:一般设置两个字体.如果浏览器第一个字体不 ...
- IOS App内嵌H5 swiper 轮播出现卡顿白屏闪烁
话说在前头:前端开发同学遇到这个问题不慌,因为接下来你要踩的坑我都帮你们踩完了,所以有了这一篇博客.希望能帮到你 轮播组件:swiper@4.5.1 (4x稳定的最后一个版本) 设备:ios版本15x ...
- SElinux 导致 Keepalived 检测脚本无法执行
哈喽大家好,我是咸鱼 今天我们来看一个关于 Keepalived 检测脚本无法执行的问题 一位粉丝后台私信我,说他部署的 keepalived 集群 vrrp_script 模块中的脚本执行失败了,但 ...
- k8s发布应用
前言 首先以SpringBoot应用为例介绍一下k8s的发布步骤. 1.从代码仓库下载代码,比如GitLab: 2.接着是进行打包,比如使用Maven: 3.编写Dockerfile文件,把步骤2产生 ...
- API接口设计规范,看这篇就足以了
优秀的设计是产品变得卓越的原因.设计API意味着提供有效的接口,可以帮助API使用者更好地了解.使用和集成,同时帮助人们有效地维护它.每个产品都需要使用手册,API也不例外. 在API领域,可以将 ...
- vue3.3.x setup 新实验性特性 defineModel 定义多个属性
由于有些业务组件需要定义多个响应式props,类似这种(比较懒,没上ts),在vue3.3.x以前,如果不用三方库,代码会变得很繁琐 <script setup> const props ...
- Solution -「NOI 2020」时代的眼泪
Description Link. 给出一个二维平面以及一些点,保证点不在同行 / 同列.每次询问求出一个子矩阵里面的顺序对. Solution 卡常,卡你吗. 膜拜 dX. 基本是把 dX 的题解贺 ...
- proto转java类时相关option配置
转载请注明出处: option java_multiple_files = true; 作用和意义:此选项指示生成的 Java 代码将被分割成多个文件而不是一个文件.每个消息类型都会生成一个单独的 J ...