LCT裸题,不会的可以来这里看看。

步入正题,现将边按a排序,依次加入每一条边,同时维护路径上的最小生成树上的最大边权,如果两点不连通,就直接连通。

如果两点已经连通,就将该边与路径上较小的一条比较,选择小的那一条即可

统计答案时,如果1与n连通就求出路径上最大值与当前的a值相加,取最小的一个。

但边权不好处理,于是我们把X—>Y路径拆成X->Z->Y,将边权放在Z的点权上即可

下面是代码

#include<bits/stdc++.h>
using namespace std;
typedef int sign;
typedef long long ll;
#define For(i,a,b) for(register sign i=(sign)a;i<=(sign)b;++i)
#define Fordown(i,a,b) for(register sign i=(sign)a;i>=(sign)b;--i)
const int N=5e4+5,M=1e5+5;
bool cmax(sign &a,sign b){return (a<b)?a=b,1:0;}
bool cmin(sign &a,sign b){return (a>b)?a=b,1:0;}
template<typename T>T read()
{
T ans=0,f=1;
char ch=getchar();
while(!isdigit(ch)&&ch!='-')ch=getchar();
if(ch=='-')f=-1,ch=getchar();
while(isdigit(ch))ans=(ans<<3)+(ans<<1)+(ch-'0'),ch=getchar();
return ans*f;
}
void file()
{
#ifndef ONLINE_JUDGE
freopen("LCT.in","r",stdin);
freopen("LCT.out","w",stdout);
#endif
}
int n,m;
int ch[N+M][2],fa[N+M],rev[N+M],edge[N+M],bl[N+M];
struct node
{
int u,v,a,b;
inline void init(){u=v=a=b=0;}
bool operator < (const node &x)const
{return a<x.a;}
}e[M];
inline void push_up(int x)
{
if(e[bl[x]].b>=e[edge[ch[x][0]]].b&&e[bl[x]].b>=e[edge[ch[x][1]]].b)edge[x]=bl[x];
else if(e[edge[ch[x][0]]].b>=e[edge[ch[x][1]]].b)edge[x]=edge[ch[x][0]];
else edge[x]=edge[ch[x][1]];
}
inline void push_down(int x)
{
if(rev[x])
{
rev[ch[x][0]]^=1;
rev[ch[x][1]]^=1;
swap(ch[x][0],ch[x][1]);
rev[x]=0;
}
}
inline bool isroot(int x){return ch[fa[x]][0]!=x&&ch[fa[x]][1]!=x;}
inline bool get(int x){return x==ch[fa[x]][1];}
inline void rotate(int x)
{
int old=fa[x],oldfa=fa[old],o=get(x);
if(!isroot(old))ch[oldfa][get(old)]=x;
fa[x]=oldfa;fa[ch[x][o^1]]=old;fa[old]=x;
ch[old][o]=ch[x][o^1];ch[x][o^1]=old;
push_up(old);push_up(x);
}
const int inf=0x3f3f3f3f;
int l[N+M],ans=inf;
inline void splay(int x)
{
l[0]=0;
int y=x;
while(1)
{
l[++l[0]]=y;
if(isroot(y))break;
y=fa[y];
}
Fordown(i,l[0],1)push_down(l[i]);
while(!isroot(x))
{
if(!isroot(fa[x]))rotate(get(x)^get(fa[x])?x:fa[x]);
rotate(x);
}
}
inline void access(int x)
{
for(register int y=0;x;y=x,x=fa[x])
{
splay(x);ch[x][1]=y;push_up(x);
}
}
inline void makeroot(int x)
{
access(x);splay(x);rev[x]^=1;
}
inline int find(int x)
{
access(x);splay(x);
while(ch[x][0])x=ch[x][0];
return x;
}
inline void cut(int x,int y)
{
makeroot(x);
access(y);splay(y);
if(ch[y][0]==x)ch[y][0]=fa[x]=0;
}
inline void link(int x,int y)
{
makeroot(x);fa[x]=y;
}
inline void deal(int i)
{
int x=e[i].u,y=e[i].v;
if(find(x)^find(y))link(x,i+n),link(i+n,y);
else
{
makeroot(x);
access(y);splay(y);
if(e[edge[y]].b>e[i].b)
{
int t=edge[y];
cut(t+n,e[t].u);
cut(t+n,e[t].v);
link(i+n,e[i].u);
link(i+n,e[i].v);
}
}
}
inline void input()
{
n=read<int>();m=read<int>();
For(i,1,m)
{
e[i].u=read<int>();
e[i].v=read<int>();
e[i].a=read<int>();
e[i].b=read<int>();
}
}
inline int cal()
{
if(find(1)^find(n))return inf;
makeroot(1);
access(n);splay(n);
return e[edge[n]].b;
}
inline void work()
{
sort(e+1,e+m+1);
e[0].init();
For(i,1,m)edge[i+n]=bl[i+n]=i;
For(i,1,m)
{
deal(i);
while(e[i].a==e[i+1].a)++i,deal(i);
cmin(ans,cal()+e[i].a);
}
printf("%d\n",ans==inf?-1:ans);
}
int main()
{
file();
input();
work();
return 0;
}

(NOI2014)(bzoj3669)魔法森林的更多相关文章

  1. 【BZOJ3669】【Noi2014】魔法森林(Link-Cut Tree)

    [BZOJ3669][Noi2014]魔法森林(Link-Cut Tree) 题面 题目描述 为了得到书法大家的真传,小 E 同学下定决心去拜访住在魔法森林中的隐 士.魔法森林可以被看成一个包含 n ...

  2. BZOJ-3669 魔法森林 Link-Cut-Tree

    意识到背模版的重要性了,记住了原理和操作,然后手打模版残了..颓我时间...... 3669: [Noi2014]魔法森林 Time Limit: 30 Sec Memory Limit: 512 M ...

  3. BZOJ 3669 【NOI2014】 魔法森林

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

  4. 【NOI2014】魔法森林

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

  5. [BZOJ3669]魔法森林

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

  6. 【NOI2014】魔法森林 - 动态加边SPFA

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

  7. 【BZOJ3669】【NOI2014】魔法森林 LCT

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

  8. bzoj3669【NOI2014】魔法森林

    题面一道最短路好题…… 开始和喻队长讨论了一下,喻队长一眼切:枚举ai的上界MAX,每次把ai小于等于MAX的边加到图里,以bi为边权跑最短路. 但是,这样做是O(ai*m)的,妥妥TLE,于是我们想 ...

  9. 【BZOJ】【3669】【NOI2014】魔法森林

    LCT动态维护MST LCT动态维护MST 我们可以枚举a,然后找从1到n的一条路径使得:这条路径上的b的最大值最小.这个路径肯定在MST上……所以枚举一遍所有的边,动态维护一个关于b值的MST即可. ...

  10. 3754. 【NOI2014】魔法森林(LCT)

    Problem 给定一个\(n\)个结点,\(m\)条边的的无向图,每条边有两个权值\(ai,bi\). 现在从\(1\)出发,要到达\(n\),每次只能沿着\(ai\le A\)且\(bi\le B ...

随机推荐

  1. Oracle 解决【ORA-01704:字符串文字太长】

    错误提示:oracle在toad中执行一段sql语句时,出现错误‘ORA-01704:字符串文字太长’.如下图: 原因:一般为包含有对CLOB字段的数据操作.如果CLOB字段的内容非常大的时候,会导致 ...

  2. Features + Git + Drush,打造你的Drupal开发与维护标准工作流

    还在为如何将本地的开发工作如何部署到生产环境而皱眉头?本文以实战历程教你如何一步步将你的工作成果从开发环境部署到生产环境. 如题所示,需要用到Features, Git, Drush:如果你还不知道他 ...

  3. Eclipse-设置格式化代码时不格式化注释

    在Eclipse里设置格式化代码时不格式化注释 今天格式化代码 发现直接format会把注释也一块格式化了,有时候会把好好的注释弄的很乱.甚为头疼. 查阅之后解决办法如下: Windows -> ...

  4. Oracle中,如何查看FRA(Flashback Recovery Area)的利用率

    例子: SQL> set linesize 300SQL> select * from V$RECOVERY_AREA_USAGE; FILE_TYPE PERCENT_SPACE_USE ...

  5. 让docker中的mysql启动时自动执行sql文件

    本文提要 本文目的不仅仅是创建一个MySQL的镜像,而是在其基础上再实现启动过程中自动导入数据及数据库用户的权限设置,并且在新创建出来的容器里自动启动MySQL服务接受外部连接,主要是通过Docker ...

  6. C#杂乱知识汇总

    :first-child{margin-top:0!important}.markdown-body>:last-child{margin-bottom:0!important}.markdow ...

  7. HTML-JS 循环 函数 递归

    [循环结构的执行步骤] 1.声明循环变量 2.判断循环条件 3.执行循环体操作 4.更新循环变量 然后,循环执行2-4,直到条件不成立时,跳出循环. while循环()中的表达式,运算结果可以是各种类 ...

  8. C#_正则表达式

    概述 正则表达式,主要是用符号描述了一类特定的文本(模式).而正则表达式引擎则负责在给定的字符串中,查找到这一特定的文本. 本文主要是列出常用的正则表达式符号,加以归类说明.本文仅仅是快速理解了正则表 ...

  9. 使用阿里云Python SDK管理ECS安全组

    准备工作 本机操作系统:CentOS7 python版本:python2.7.5 还需要准备如下信息: 一个云账号.Access Key ID.Access Key Secret.安全组ID.Regi ...

  10. GitHub笔记(一)——本地库基础操作

    零.基础概念理解——可以访问廖雪峰老师的网站https://www.liaoxuefeng.com/wiki/0013739516305929606dd18361248578c67b8067c8c01 ...