传送门

题目大意

给定 \(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】 魔法森林---解题报告的更多相关文章

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

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

  2. NOI2014魔法森林题解报告

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

  3. NOI2014 魔法森林

    3669: [Noi2014]魔法森林 Time Limit: 30 Sec  Memory Limit: 512 MBSubmit: 106  Solved: 62[Submit][Status] ...

  4. bzoj 3669: [Noi2014]魔法森林 动态树

    3669: [Noi2014]魔法森林 Time Limit: 30 Sec  Memory Limit: 512 MBSubmit: 363  Solved: 202[Submit][Status] ...

  5. BZOJ 3669: [Noi2014]魔法森林( LCT )

    排序搞掉一维, 然后就用LCT维护加边MST. O(NlogN) ------------------------------------------------------------------- ...

  6. bzoj 3669: [Noi2014]魔法森林

    bzoj 3669: [Noi2014]魔法森林 Description 为了得到书法大家的真传,小E同学下定决心去拜访住在魔法森林中的隐士.魔法森林可以被看成一个包含个N节点M条边的无向图,节点标号 ...

  7. BZOJ_3669_[Noi2014]魔法森林_LCT

    BZOJ_3669_[Noi2014]魔法森林_LCT Description 为了得到书法大家的真传,小E同学下定决心去拜访住在魔法森林中的隐士.魔法森林可以被看成一个包含个N节点M条边的无向图,节 ...

  8. bzoj 3669: [Noi2014]魔法森林 (LCT)

    链接:https://www.lydsy.com/JudgeOnline/problem.php?id=3669 题面: 3669: [Noi2014]魔法森林 Time Limit: 30 Sec  ...

  9. 「luogu2387」[NOI2014] 魔法森林

    「luogu2387」[NOI2014] 魔法森林 题目大意 \(n\) 个点 \(m\) 条边的无向图,每条边上有两个权值 \(a,b\),求从 \(1\) 节点到 \(n\) 节点 \(max\{ ...

  10. P2387 [NOI2014]魔法森林(LCT)

    P2387 [NOI2014]魔法森林 LCT边权维护经典题 咋维护呢?边化为点,边权变点权. 本题中我们把边对关键字A进行排序,动态维护关键字B的最小生成树 加边后出现环咋办? splay维护最大边 ...

随机推荐

  1. 论文解读(BERT-DAAT)《Adversarial and Domain-Aware BERT for Cross-Domain Sentiment Analysis》

    论文信息 论文标题:Adversarial and Domain-Aware BERT for Cross-Domain Sentiment Analysis论文作者:论文来源:2020 ACL论文地 ...

  2. mysql根据mysqlbinlog恢复找回被删除的数据库

    年初和朋友一起做了个项目,到现在还没收到钱呢,今天中午时候突然听说之前的数据库被攻击了,业务数据库全部被删除.看有没有什么办法恢复,要是恢复不了,肯定也别想拿钱了吧? README FOR RECOV ...

  3. 使用C#的窗体显示与隐藏动画效果方案 - 开源研究系列文章

    今天继续研究C#的WinForm的显示动画效果. 上次我们实现了无边框窗体的显示动画效果(见博文:基于C#的无边框窗体动画效果的完美解决方案 - 开源研究系列文章 ),这次介绍的是未在任务栏托盘中窗体 ...

  4. 【后端面经-数据库】Redis详解——Redis基本概念和特点

    目录 1. Redis基本概念 2. Redis特点 2.1 优点 2.2 缺点 3. Redis的应用场景 面试模拟 参考资料 声明:Redis的相关知识是面试的一大热门知识点,同时也是一个庞大的体 ...

  5. python机器学习经典算法代码示例及思维导图(数学建模必备)

    最近几天学习了机器学习经典算法,通过此次学习入门了机器学习,并将经典算法的代码实现并记录下来,方便后续查找与使用. 这次记录主要分为两部分:第一部分是机器学习思维导图,以框架的形式描述机器学习开发流程 ...

  6. MIPS寄存器堆

    实验目的 熟悉并掌握 MIPS 计算机中寄存器堆的原理和设计方法 理解源操作数/目的操作数的概念 实验环境 Vivado 集成开发环境 MIPS寄存器 寄存器R0的值恒为0. 模块接口设计 1个写端口 ...

  7. 【Python进阶-PyQt5】00搭建PyQt5环境

    1.创建独立开发虚拟环境 1.1虚拟环境简介 我们编写的程序,有时用到的Python库是不一样的,比如说开发桌面应用程序我们主要用到PyQt5相关的Python库.开发Web应用程序我们主要用到Dja ...

  8. 文心一言 VS 讯飞星火 VS chatgpt (103)-- 算法导论10.1 1题

    一.用go语言,仿照图 10-1,画图表示依次执行操作 PUSH(S,4).PUSH(S,1).PUSH(S,3).POP(S).PUSH(S,8)和 POP(S)每一步的结果,栈 S初始为空,存储于 ...

  9. c语言代码练习2(2)改进

    //利用for循环计算1-10阶乘的和#define _CRT_SECURE_NO_WARNINGS 1 #include <stdio.h> int main( ) { int num ...

  10. Python实现与MySQL长连接的客户端

    下面的代码是使用Python建立的和MySQL长连接的简单客户端示例. 当和MySQL的连接断开后,会自动进行重连(被动式的重连,即只有调用增self.execute().删self.execute( ...