【BZOJ3669】【NOI2014】魔法森林 LCT

时间:2022-06-23 06:29:40

题目描述

  给你一个\(n\)个点\(m\)条边的图,每条边有两个边权\(a,b\)。请你找出从\(1\)到\(n\)一条路径,使得这条路径上边权\(a\)的最大值\(+\)边权\(b\)的最大值最小。

  \(n\leq 50000,m\leq 100000\)

题解

  我们可以考虑求出当边权\(a\leq\)某个数时边权\(b\)的最大值。

  先把边按边权\(a\)从小到大排序,依次加入,用LCT维护当前边权\(b\)的最小生成树。如果这两个点已经联通,就判断这两个点路径上边的边权\(b\)的最大值,如果大于当前这条边的边权\(b\),就把这条边删掉。否则就不加入这条边。

  每加完一条边我们就可以认为从\(1\)到\(n\)的边权\(a\)的最大值为当前这条边的边权\(a\)(否则就会在之前更新到),然后查询\(1\)到\(n\)的边权\(b\)的最大值,更新答案。

  时间复杂度:\(O(m\log n)\)

代码

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cstdlib>
#include<ctime>
#include<utility>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int> pii;
namespace lct
{
int a[200010][2];
int f[200010];
pii v[200010];
pii s[200010];
int r[200010];
int root(int x)
{
return !f[x]||(a[f[x]][0]!=x&&a[f[x]][1]!=x);
}
void reverse(int x)
{
swap(a[x][0],a[x][1]);
r[x]^=1;
}
void push(int x)
{
if(r[x])
{
if(a[x][0])
reverse(a[x][0]);
if(a[x][1])
reverse(a[x][1]);
r[x]=0;
}
}
void mt(int x)
{
s[x]=max(v[x],max(s[a[x][0]],s[a[x][1]]));
}
void rotate(int x)
{
if(root(x))
return;
int p=f[x];
int q=f[p];
int ps=(x==a[p][1]);
int qs=(p==a[q][1]);
int ch=a[x][ps^1];
if(!root(p))
a[q][qs]=x;
a[x][ps^1]=p;
a[p][ps]=ch;
if(ch)
f[ch]=p;
f[p]=x;
f[x]=q;
mt(p);
mt(x);
}
void clear(int x)
{
if(!root(x))
clear(f[x]);
push(x);
}
void splay(int x)
{
clear(x);
int p,q;
while(!root(x))
{
p=f[x];
if(!root(p))
{
q=f[p];
if((p==a[q][1])==(x==a[p][1]))
rotate(p);
else
rotate(x);
}
rotate(x);
}
}
void access(int x)
{
int y=x,t=0;
while(x)
{
splay(x);
a[x][1]=t;
mt(x);
t=x;
x=f[x];
}
splay(y);
}
void change(int x)
{
access(x);
reverse(x);
}
int findroot(int x)
{
access(x);
while(a[x][0])
x=a[x][0];
splay(x);
return x;
}
pii query(int x,int y)
{
change(x);
access(y);
return s[y];
}
void link(int x,int y)
{
change(x);
f[x]=y;
}
void cut(int x,int y)
{
change(x);
access(y);
f[a[y][0]]=0;
a[y][0]=0;
mt(y);
}
}
struct edge
{
int x,y;
int a,b;
};
edge a[100010];
int cmp(edge a,edge b)
{
return a.a<b.a;
}
int main()
{
// freopen("bzoj3669.in","r",stdin);
// freopen("bzoj3669.out","w",stdout);
int n,m;
scanf("%d%d",&n,&m);
int i;
for(i=1;i<=m;i++)
scanf("%d%d%d%d",&a[i].x,&a[i].y,&a[i].a,&a[i].b);
sort(a+1,a+m+1,cmp);
int ans=0x7fffffff;
for(i=1;i<=m;i++)
{
if(a[i].x==a[i].y)
continue;
if(lct::findroot(a[i].x)==lct::findroot(a[i].y))
{
pii s=lct::query(a[i].x,a[i].y);
if(a[i].b>=a[s.second].b)
continue;
lct::cut(s.second+n,a[s.second].x);
lct::cut(s.second+n,a[s.second].y);
}
lct::v[i+n]=pii(a[i].b,i);
lct::link(a[i].x,i+n);
lct::link(a[i].y,i+n);
if(lct::findroot(1)==lct::findroot(n))
ans=min(ans,a[i].a+lct::query(1,n).first);
}
if(ans==0x7fffffff)
ans=-1;
printf("%d\n",ans);
return 0;
}

【BZOJ3669】【NOI2014】魔法森林 LCT的更多相关文章

  1. bzoj3669&colon; &lbrack;Noi2014&rsqb;魔法森林 lct版

    先上题目 bzoj3669: [Noi2014]魔法森林 这道题首先每一条边都有一个a,b 我们按a从小到大排序 每次将一条路劲入队 当然这道题权在边上 所以我们将边化为点去连接他的两个端点 当然某两 ...

  2. bzoj3669&colon; &lbrack;Noi2014&rsqb;魔法森林 lct

    记得去年模拟赛的时候好像YY出二分答案枚举a,b的暴力,过了55欸 然后看正解,为了将两维变成一维,将a排序,模拟Kruskal的加边过程,同时维护1到n的最大值,加入一条边e(u,v,a,b)时有以 ...

  3. &lbrack;bzoj3669&rsqb;&lbrack;Noi2014&rsqb;魔法森林——lct

    Brief description 给定一个无向图,求从1到n的一条路径使得这条路径上最大的a和b最小. Algorithm Design 以下内容选自某HN神犇的blog 双瓶颈的最小生成树的感觉, ...

  4. BZOJ 3669&colon; &lbrack;Noi2014&rsqb;魔法森林&lpar; LCT &rpar;

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

  5. bzoj 3669&colon; &lbrack;Noi2014&rsqb;魔法森林 &lpar;LCT)

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

  6. &lbrack;NOI2014&rsqb;魔法森林 LCT

    题面 [NOI2014]魔法森林 题解 一条路径的代价为路径上的\(max(a[i]) + max(b[i])\),因为一条边同时有$a[i], b[i]$2种权值,直接处理不好同时兼顾到,所以我们考 ...

  7. loj2245 &lbrack;NOI2014&rsqb;魔法森林 LCT

    [NOI2014]魔法森林 链接 loj 思路 a排序,b做动态最小生成树. 把边拆成点就可以了. uoj98.也许lct复杂度写假了..越卡常,越慢 代码 #include <bits/std ...

  8. 【BZOJ3669】&lbrack;Noi2014&rsqb;魔法森林 LCT

    终于不是裸的LCT了...然而一开始一眼看上去这是kruskal..不对,题目要求1->n的路径上的每个点的两个最大权值和最小,这样便可以用LCT来维护一个最小生成路(瞎编的...),先以a为关 ...

  9. BZOJ3669&lbrack;Noi2014&rsqb;魔法森林——kruskal&plus;LCT

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

  10. BZOJ3669&colon; &lbrack;Noi2014&rsqb;魔法森林&lpar;瓶颈生成树 LCT&rpar;

    Time Limit: 30 Sec  Memory Limit: 512 MBSubmit: 3558  Solved: 2283[Submit][Status][Discuss] Descript ...

随机推荐

  1. tomcat配置https

    1.开启使用https协议 编辑tomcat目录下的conf/server.xml文件 <Connector port="443" protocol="HTTP/1 ...

  2. Javascript常用方法函数收集(一)

    1.字符串长度截取 function cutstr(str, len) { var temp, icount = 0, patrn = /[^\x00-\xff]/, strre = "&q ...

  3. Echars详解

    简介 ECharts,缩写来自Enterprise Charts,商业级数据图表,一个纯Javascript的图表库,可以流畅的运行在PC和移动设备上,兼容当前绝大部分浏览器(IE6/7/8/9 /1 ...

  4. matlab调用opencv函数的配置

    环境: VS2010 活动解决方案平台x64 WIN 8.1 Opencv 2.4.3 Matlab 2012a 1.  首先保证vs2010能正确调用opencv函数, 2.  Matlab中选择编 ...

  5. 在top命令下kill和renice进程

    For common process management tasks, top is so great because it gives an overview of the most active ...

  6. JAVA Set 交集,差集,并集

    /** * Created by yuhui on 2017/7/11 0011. */ import java.util.HashSet; import java.util.Set; public ...

  7. Java计算文件MD5值&lpar;支持大文件&rpar;

    import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.securit ...

  8. AI之旅(3):升维与最小二乘法

    前置知识   矩阵的逆 知识地图   首先我们将了解一种叫升维的方法,用已有特征构造更多的特征.接着通过对空间与投影建立一定的概念后,推导出最小二乘法. 当特征数量不足时   在上一篇<初识线性 ...

  9. lua的table元类

    Lua中提供的元表是用于帮助Lua数据变量完成某些非预定义功能的个性化行为,如两个table的相加.假设a和b都是table,通过元表可以定义如何计算表达式a+b.当Lua试图将两个table相加时, ...

  10. UML和模式应用4:初始阶段&lpar;5&rpar;--用例编写的准则

    1.前言 本文主要介绍用例编写时所遵循的几条基本准则. 2.用例编写的准则 2.1 以本质的风格编写用例 如系统认证,而不要说 需要输入ID进行认证等 2.2 编写简洁的用例 如系统认证,不要说 这个 ...