终于不是裸的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

最新文章

  1. SQLServer文件收缩-图形化+命令
  2. 数据结构笔记--二叉查找树概述以及java代码实现
  3. 实现标记datagridview标题并导出Excel的功能
  4. webapp开发经验总结
  5. 放松时刻——C#分割字符串
  6. linux下的文件操作——批量重命名
  7. 防止程序启动两次的方法CreateMutex()
  8. CentOS、Ubuntu、Debian三个linux比较异同
  9. Java内存分配及垃圾回收机制(未完待待续)
  10. mysql时间戳与日期格式的相互转换
  11. sql查询化繁为简 告别rs.getString(&quot;XX&quot;),bean属性赋值setXX(&quot;XX&quot;)
  12. Swing中经常会遇到的若干问题——JTable(持续更新)
  13. 【Java每日一题】20170224
  14. ImportError: No module named MySQLdb问题的解决
  15. 问题:grid卸载后重新安装时ASM磁盘识别不到了
  16. Linux内核分析 笔记二 操作系统是如何工作的 ——by王玥
  17. 安卓程序代写 网上程序代写[原]C语言基础
  18. python之协程gevent模块
  19. sql performance Kill Lock
  20. fegin---@FeginClient参数介绍

热门文章

  1. java源码分析:Arrays.sort
  2. can&#39;t open a connection to site &#39;syb_backup&#39;
  3. 百度地图API简单应用
  4. 【09-14】eclipse学习笔记
  5. javascript数据结构与算法--链表
  6. 大熊君学习html5系列之------WebStorage(客户端轻量级存储方案)
  7. 关于使用 no-js (Modernizr)
  8. JDI tutorial (trace example)
  9. UI第九节——UIProgressView
  10. getcwd()和dirname(__FILE__)的区别