3669: [Noi2014]魔法森林

Time Limit: 30 Sec  Memory Limit: 512 MB
Submit: 363  Solved: 202
[Submit][Status]

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

  按照a值排序,动态维护b值的最小生成树。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define MAXN 110000
#define MAXM 210000
#define MAXT MAXN*2
#define INF 0x3f3f3f3f
int n,m;
int ch[MAXT][],pnt[MAXT],val[MAXT],mx[MAXT],mt[MAXT];
bool rev[MAXT];
int stack[MAXT],tops=-;
inline bool is_root(int x)
{
return !pnt[x] || (ch[pnt[x]][]!=x && ch[pnt[x]][]!=x);
}
void update(int now)
{
if (mx[ch[now][]]>=mx[ch[now][]])
{
mx[now]=mx[ch[now][]];
mt[now]=mt[ch[now][]];
}else
{
mx[now]=mx[ch[now][]];
mt[now]=mt[ch[now][]];
}
if (val[now]>mx[now])
{
mx[now]=val[now];
mt[now]=now;
}
}
void reverse(int now)
{
swap(ch[now][],ch[now][]);
rev[now]^=;
}
void down(int now)
{
if (rev[now])
{
reverse(ch[now][]);
reverse(ch[now][]);
rev[now]=false;
}
}
void rotate(int now)
{
int p=pnt[now],anc=pnt[p];
int dir=ch[p][]==now;
if (!is_root(p))
ch[anc][ch[anc][]==p]=now;
pnt[now]=anc;
pnt[ch[now][dir]]=p;
ch[p][-dir]=ch[now][dir];
pnt[p]=now;
ch[now][dir]=p;
update(p);
update(now);
}
void splay(int now)
{
int x=now;
stack[++tops]=x;
while (!is_root(x))
{
x=pnt[x];
stack[++tops]=x;
}
while (~tops)down(stack[tops--]);
while (!is_root(now))
{
int p=pnt[now],anc=pnt[p];
if (is_root(p))
rotate(now);
else if ((ch[anc][]==p) == (ch[p][]==now))
rotate(p),rotate(now);
else
rotate(now),rotate(now);
}
}
int access(int now)
{
int son=;
while (now)
{
splay(now);
ch[now][]=son;
update(now);
son=now;
now=pnt[now];
}
return son;
}
void make_root(int now)
{
access(now);
splay(now);
reverse(now);
}
void Create_edge(int x,int y)
{
//cout<<"Add:"<<x<<" "<<y<<endl;
make_root(x);
make_root(y);
pnt[y]=x;
ch[x][]=y;
update(x);
}
void Erase_edge(int x,int y)
{
//cout<<"Del:"<<x<<" "<<y<<endl;
make_root(x);
access(y);
splay(x);
if (ch[x][]==y)
{
splay(y);
ch[y][]=pnt[x]=;
update(y);
}else if (ch[x][]==y)
{
ch[x][]=pnt[y]=;
update(x);
}else throw ;
}
pair<int,int> Query_path(int x,int y)
{
//cout<<"Qry:"<<x<<" "<<y<<endl;
make_root(x);
int t=access(y);
return make_pair(mx[t],mt[t]-n);
}
struct aaa
{
int x,y,a,b,id;;
bool flag;
}l[MAXM],l0[MAXN];;
bool cmp_a(aaa a1,aaa a2)
{
return a1.a<a2.a;
}
bool cmp_b(aaa a1,aaa a2)
{
return a1.b<a2.b;
}
int uf[MAXN];
int get_fa(int now)
{
return uf[now]==now ? now : uf[now]=get_fa(uf[now]);
}
bool comb_uf(int x,int y)
{
x=get_fa(x);
y=get_fa(y);
if (x==y)return false;
uf[x]=y;
return true;
}
int main()
{
freopen("input.txt","r",stdin);
int i,j,k,x,y,z;
scanf("%d%d",&n,&m);
for (i=;i<=n;i++)
uf[i]=i;
for (i=;i<=m;i++)
{
scanf("%d%d%d%d",&l[i].x,&l[i].y,&l[i].a,&l[i].b);
l[i].id=i;
val[i+n]=l[i].b;
l0[i]=l[i];
}
sort(l+,l+m+,cmp_a);
int ans=INF;
for (i=;i<=m;i++)
{
if (comb_uf(l[i].x,l[i].y))
{
l[i].flag=true;
Create_edge(l[i].x,l[i].id+n);
Create_edge(l[i].y,l[i].id+n);
}else
{
pair<int,int> pr;
pr=Query_path(l[i].x,l[i].y);
if (pr.first<=l[i].b)continue;
Erase_edge(l0[pr.second].x,pr.second+n);
Erase_edge(l0[pr.second].y,pr.second+n);
Create_edge(l[i].x,l[i].id+n);
Create_edge(l[i].y,l[i].id+n);
}
if (get_fa()==get_fa(n))
{
ans=min(ans,l[i].a+Query_path(,n).first);
// cout<<ans<<endl;
}
}
if (ans==INF)
printf("-1\n");
else
printf("%d\n",ans);
}

bzoj 3669: [Noi2014]魔法森林 动态树的更多相关文章

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

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

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

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

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

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

  4. bzoj 3669: [Noi2014]魔法森林 -- 动点spfa

    3669: [Noi2014]魔法森林 Time Limit: 30 Sec  Memory Limit: 512 MB 动点spfa Description 为了得到书法大家的真传,小E同学下定决心 ...

  5. 图论 BZOJ 3669 [Noi2014]魔法森林

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

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

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

  7. BZOJ 3669: [Noi2014]魔法森林 [LCT Kruskal | SPFA]

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

  8. BZOJ 3669 [Noi2014]魔法森林(贪心+LCT)

    [题目链接] http://www.lydsy.com/JudgeOnline/problem.php?id=3669 [题目大意] 给出一张图,每条边上有两个值ai和bi,现在需要求出一条1到N的路 ...

  9. [BZOJ 3669] [Noi2014] 魔法森林 【LCT】

    题目链接:BZOJ - 3669 题目分析 如果确定了带 x 只精灵A,那么我们就是要找一条 1 到 n 的路径,满足只经过 Ai <= x 的边,而且要使经过的边中最大的 Bi 尽量小. 其实 ...

随机推荐

  1. XRDP与VNC的关系

    如果仅仅安装XRDP协议.是不能在windows上使用远程桌面连接到Ubuntu. 还须要安装VNCServer才行. 所以,XRDP启动之后.系统会自己主动启动一个VNC会话进程监听服务. 当我们通 ...

  2. Solr配置与简单Demo[转]

    Solr配置与简单Demo 简介: solr是基于Lucene Java搜索库的企业级全文搜索引擎,目前是apache的一个项目.它的官方网址在http://lucene.apache.org/sol ...

  3. \n 与 \r 在记事本中的内容表现方式 原创

    总结:[0D,0A]的顺序才可以记事本才可以正常显示回车换行,其他EDITPLUS ,等编缉工具在下面三种情况下都可以换行 原始数据与表现形式     [0D,0A]序列才可以正常显示回车换行 --- ...

  4. gdb调试运行时的程序小技巧

    使用gdb调试运行时的程序小技巧 标签: 未分类 gdb pstack | 发表时间:2012-10-15 04:32 | 作者:士豪 分享到: 出处:http://rdc.taobao.com/bl ...

  5. FileZilla命令行实现文件上传以及CreateProcess实现静默调用

    应用需求:         用户在选择渲染作业时面临两种情况:一是选择用户远程存储上的文件:二是选择本地文件系统中的文件进行渲染.由于渲染任务是在远程主机上进行的,实际进行渲染时源文件也是在ftp目录 ...

  6. Sending e-mail with Spring MVC---reference

    reference from:http://www.codejava.net/frameworks/spring/sending-e-mail-with-spring-mvc Table of con ...

  7. java 流程执行 循环 foreach循环

    一. if分支 1. 结构  if  else if   else 2.执行原则 if  if  if 结构  会一直去执行()里的判断语句 if else if  else if 结构  只要一条( ...

  8. ASP.NET中常用重置数据的方法

    aspx: <asp:Repeater ID="rptProlist" runat="server" onitemdatabound="rptP ...

  9. Python实战:Python爬虫学习教程,获取电影排行榜

    Python应用现在如火如荼,应用范围很广.因其效率高开发迅速的优势,快速进入编程语言排行榜前几名.本系列文章致力于可以全面系统的介绍Python语言开发知识和相关知识总结.希望大家能够快速入门并学习 ...

  10. 为什么要设置Java环境变量(详解)

    关于java环境变量配置讲解: 1. PATH环境变量.作用是指定命令搜索路径,在shell下面执行命令时,它会到PATH变量所指定的路径中查找看是否能找到相应的命令程序.我们需要把 jdk安装目录下 ...