终于不是裸的LCT了。。。然而一开始一眼看上去这是kruskal。。不对,题目要求1->n的路径上的每个点的两个最大权值和最小,这样便可以用LCT来维护一个最小生成路(瞎编的。。。),先以a为关键字排序,然后加边,所以每次加入一条边时a一定是最大的,考虑b的大小,当形成环时,考虑用当前边替换掉环内b最大的边,当然是当前边b小于权值最大的边拉!

  Tips:1.注意LCT要把每条边也作为一个节点,方便连接,然后每个节点维护所在边在边集里的编号即可。

 #include <iostream>
#include <cstdio>
#include <algorithm>
#define N 50050
#define M 100100
#define inf 0x7fffffff
using namespace std;
int n,m,ans;
struct E{int x,y,a,b;}e[M];
struct node
{
node *fa,*ch[];
void init();
int pos,rpos;
bool rev;
bool chr() {return this==fa->ch[];}
bool isrt() {return this!=fa->ch[] && this!=fa->ch[];}
void setc(node *x,int t) {this->ch[t]=x; x->fa=this;}
void push_up();
void push_down();
/* void push_down()
{
if (this==null) return;
if (!x->isrt()) x->fa->push_down();
if (rev)
{
ch[1]->rev^=1;
ch[0]->rev^=1;
swap(ch[1],ch[0]);
rev=0;
}
}
void push_up()
{
if (this==null) return;
pos=rpos;
if (ch[0]!=null && e[pos].b<e[ch[0]->pos].b) pos=ch[0]->pos;
if (ch[1]!=null && e[pos].b<e[ch[1]->pos].b) pos=ch[1]->pos;
}*/
}pool[N+M],*pt=pool,*point[N],*et[M],*null;
void node::init() {ch[]=ch[]=fa=null; pos=; rev=; rpos=;}
void node::push_up()
{
if (this==null) return;
pos=rpos;
if (ch[]!=null && e[pos].b<e[ch[]->pos].b) pos=ch[]->pos;
if (ch[]!=null && e[pos].b<e[ch[]->pos].b) pos=ch[]->pos;
}
void node::push_down()
{
if (this==null) return;
if (!this->isrt()) this->fa->push_down();
if (rev)
{
if (ch[]!=null) ch[]->rev^=;
if (ch[]!=null) ch[]->rev^=;
swap(ch[],ch[]);
rev=;
}
}
namespace LCT
{
node *NewNode()
{
pt++;
pt->init();
return pt;
}
void rotate(node *x)
{
node *r=x->fa;
if (x==null || r==null) return;
int t=x->chr();
if (r->isrt()) x->fa=r->fa;
else r->fa->setc(x,r->chr());
r->setc(x->ch[t^],t);
x->setc(r,!t);
x->push_up(); r->push_up();
}
void Splay(node *x)
{
x->push_down();
for (;!x->isrt();rotate(x))
if (!x->fa->isrt())
if (x->chr()==x->fa->chr()) rotate(x->fa);
else rotate(x);
x->push_up();
}
void Access(node *x)
{
node *r=null;
for (;x!=null;r=x,x=x->fa)
{
Splay(x);
x->ch[]=r;
}
}
void MoveRoot(node *x)
{
Access(x);
Splay(x);
x->rev^=;
}
void Link(node *x,node *y)
{
MoveRoot(x);
x->fa=y;
}
void Cut(node *x,node *y)
{
MoveRoot(x);
Access(y); Splay(y);
y->ch[]->fa=null; y->ch[]=null;
}
node *Find(node *x)
{
Access(x);
Splay(x);
while (x->ch[]!=null) x=x->ch[];
return x;
}
int Query(node *x,node *y)
{
MoveRoot(x);
Access(y);Splay(y);
return y->pos;
}
}
inline int read()
{
char c;
int ans=,f=;
while (!isdigit(c=getchar())) if (c=='-') f=-;
ans=c-'';
while (isdigit(c=getchar())) ans=ans*+c-'';
return ans*f;
}
inline bool cmp (E a,E b) {return a.a<b.a;}
using namespace LCT;
int main()
{
n=read();m=read();
null=pt++;
null->init();
for (int i=;i<=m;i++) {e[i].x=read(); e[i].y=read(); e[i].a=read(); e[i].b=read();}
for (int i=;i<=n;i++) point[i]=NewNode();
sort(e+,e+m+,cmp);
ans=inf;e[].b=-inf;
for (int i=;i<=m;i++)
{
int x=e[i].x,y=e[i].y,b=e[i].b;
et[i]=NewNode(); et[i]->pos=et[i]->rpos=i;
if (Find(point[x])==Find(point[y]))
{
int pos=Query(point[x],point[y]);
if (e[pos].b>b)
{
Cut(et[pos],point[e[pos].x]);
Cut(et[pos],point[e[pos].y]);
Link(et[i],point[x]);
Link(et[i],point[y]);
}
}
else
{
Link(et[i],point[x]);
Link(et[i],point[y]);
}
if (Find(point[])==Find(point[n])) ans=min(ans,e[i].a+e[Query(point[],point[n])].b);
}
if (ans!=inf) printf("%d\n",ans);
else printf("-1\n");
return ;
}

Description

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

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

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

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

Input

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

Output

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

Sample Input

【输入样例1】
4 5
1 2 19 1
2 3 8 12
2 4 12 15
1 3 17 8
3 4 1 17

【输入样例2】

3 1
1 2 1 1

Sample Output

【输出样例1】

32
【样例说明1】
如果小E走路径1→2→4,需要携带19+15=34个守护精灵;
如果小E走路径1→3→4,需要携带17+17=34个守护精灵;
如果小E走路径1→2→3→4,需要携带19+17=36个守护精灵;
如果小E走路径1→3→2→4,需要携带17+15=32个守护精灵。
综上所述,小E最少需要携带32个守护精灵。

【输出样例2】

-1
【样例说明2】
小E无法从1号节点到达3号节点,故输出-1。

HINT

2<=n<=50,000

0<=m<=100,000

1<=ai ,bi<=50,000

Source

【BZOJ3669】[Noi2014]魔法森林 LCT的更多相关文章

  1. bzoj3669: [Noi2014]魔法森林 lct版

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

  2. bzoj3669: [Noi2014]魔法森林 lct

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

  3. [bzoj3669][Noi2014]魔法森林——lct

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

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

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

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

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

  6. [NOI2014]魔法森林 LCT

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

  7. loj2245 [NOI2014]魔法森林 LCT

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

  8. BZOJ3669[Noi2014]魔法森林——kruskal+LCT

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

  9. BZOJ3669: [Noi2014]魔法森林(瓶颈生成树 LCT)

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

随机推荐

  1. ETL简介

    1.ETL的定义 ETL分别是“Extract”.“ Transform” .“Load”三个单词的首字母缩写也就是“抽取”.“转换”.“装载”,但我们日常往往简称其为数据抽取. ETL是BI/DW( ...

  2. Coursera-Getting and Cleaning Data-week1-课程笔记

    博客总目录,记录学习R与数据分析的一切:http://www.cnblogs.com/weibaar/p/4507801.html -- Sunday, January 11, 2015 课程概述 G ...

  3. 第3月第2天 find symbolicatecrash 生产者-消费者 ice 引用计数

    1.linux find export find /Applications/Xcode.app/ -name symbolicatecrash -type f export DEVELOPER_DI ...

  4. jquery.validate.js插件使用

    jQuery验证控件jquery.validate.js使用说明+中文API 官网地址:http://bassistance.de/jquery-plugins/jquery-plugin-valid ...

  5. 浏览器兼容innerText nextElementSibling firstElementChild

    //下面是封装的方法,可以直接使用 //获dom对象的innerText的取值 function getInnerText(element){ //判断浏览器是否支持innerText if(type ...

  6. [Linux]系统调用理解(3)

    本文介绍了Linux下的进程的一些概念,并着重讲解了与Linux进程管理相关的重要系统调用wait,waitpid和exec函数族,辅助一些例程说明了它们的特点和使用方法. 1.7 背景 在前面的文章 ...

  7. Sublime Text 2报“Decode error - output not utf-8”错误的解决办法

    [Decode error - output not utf-8] [Decode error - output not utf-8]   应该怎么办?   这是因为python配置的编译环境的编码不 ...

  8. PhpStorm Git 配置(解决文件没有变色的问题)

    摘要: PhpStorm Git 配置 首先需要安装windows下的Git版本,网上有很多我下载的是msysgit反正都差不多,不会的自己百度. 其次打开PhpStorm,点击File ,Setti ...

  9. 关于Qt creator 无法使用fcitx输入中文的问题折腾

    环境: 系统ubuntu16.04amd64,qt5.4.2 安装完qt5.4后,在编写代码时,发现无法输入中文,离开qt creator 就立刻正常.原因似乎是qt对fcitx支持. 解决方法我是参 ...

  10. 【leetcode】Maximum Subarray (53)

    1.   Maximum Subarray (#53) Find the contiguous subarray within an array (containing at least one nu ...