【题目分析】

大意就是有一张图,边权有两个值,ai和bi

找到一条路径,使得路径上的max(ai)+max(bi)最小。

遇到有两个权值或者多个权值的时候,如果他们互相影响,试着用分块搞一搞。

如果互不影响,先用排序搞掉一维。

这显然a与b分开计算,直接按照ai排序。

之后不断加入,然后计算在bi上的最短路,更新答案即可。

SPFA代码相当好写(复杂度一直是玄学如果重边比较多,几乎可以达到nm)

这么玄学的复杂度居然AC了,真实神奇。

#include <cstdio>
#include <cstring>
#include <cmath>
#include <cstdlib> #include <map>
#include <set>
#include <queue>
#include <string>
#include <iostream>
#include <algorithm> using namespace std; #define maxn 300005
#define inf 0x3f3f3f3f
#define F(i,j,k) for (int i=j;i<=k;++i)
#define D(i,j,k) for (int i=j;i>=k;--i) void Finout()
{
#ifndef ONLINE_JUDGE
freopen("in.txt","r",stdin);
// freopen("out.txt","w",stdout);
#endif
} int Getint()
{
int x=0,f=1; char ch=getchar();
while (ch<'0'||ch>'9') {if (ch=='-') f=-1; ch=getchar();}
while (ch>='0'&&ch<='9') {x=x*10+ch-'0'; ch=getchar();}
return x*f;
} int n,m,dis[maxn],ans=inf;
struct edge{int l,r,a,b;}e[maxn];
bool cmp(edge x,edge y)
{return x.a<y.a;}
int h[maxn<<1],ne[maxn<<1],to[maxn<<1],w[maxn<<1],en=0; void add(int a,int b,int c)
{
to[en]=b; w[en]=c; ne[en]=h[a]; h[a]=en++;
to[en]=a; w[en]=c; ne[en]=h[b]; h[b]=en++;
} int inq[maxn];
queue <int> q; void SPFA(int S)
{
while (!q.empty()) q.pop();
q.push(S);
while (!q.empty())
{
int x=q.front();q.pop();inq[x]=0;
// cout<<"on "<<x<<endl;
for (int i=h[x];i>=0;i=ne[i])
{
if (dis[to[i]]>max(dis[x],w[i]))
{
dis[to[i]]=max(dis[x],w[i]);
if (!inq[to[i]])
{
inq[to[i]]=1;
q.push(to[i]);
}
}
}
}
} int main()
{
Finout();
n=Getint(); m=Getint();
F(i,1,m)
{
e[i].l=Getint();
e[i].r=Getint();
e[i].a=Getint();
e[i].b=Getint();
}
sort(e+1,e+m+1,cmp);
memset(h,-1,sizeof h);
memset(dis,0x3f,sizeof dis);
dis[1]=0;
F(i,1,m)
{
add(e[i].l,e[i].r,e[i].b);
SPFA(e[i].l);SPFA(e[i].r);
ans=min(ans,dis[n]+e[i].a);
}
if (ans==inf) cout<<"-1"<<endl;
else cout<<ans<<endl;
}

之后想一想,用LCT去维护边权貌似复杂度更好。

也是按照ai排序,然后加入边,如果构成环,就删去权值最大的一个。

然后统计答案。

维护边权的时候,直接维护比较难,可以把原图边和点都看作点,然后互相连接,这样就只有点权了。

写起来也很爽。

#include <cstdio>
#include <cstring>
#include <cmath>
#include <cstdlib> #include <map>
#include <set>
#include <queue>
#include <string>
#include <iostream>
#include <algorithm> using namespace std; #define maxn 500005
#define inf 0x3f3f3f3f
#define F(i,j,k) for (int i=j;i<=k;++i)
#define D(i,j,k) for (int i=j;i>=k;--i) void Finout()
{
#ifndef ONLINE_JUDGE
freopen("in.txt","r",stdin);
// freopen("out.txt","w",stdout);
#endif
} int Getint()
{
int x=0,f=1; char ch=getchar();
while (ch<'0'||ch>'9') {if (ch=='-') f=-1; ch=getchar();}
while (ch>='0'&&ch<='9') {x=x*10+ch-'0'; ch=getchar();}
return x*f;
} int mx[maxn],v[maxn],n,m,ans=inf,sta[maxn],top=0;
int fa[maxn],ch[maxn][2],rev[maxn],val[maxn];
struct edge{int u,v,a,b;}e[maxn];
bool cmp(edge x,edge y){return x.a<y.a;} bool isroot(int x)
{return ch[fa[x]][0]!=x&&ch[fa[x]][1]!=x;} void update(int x)
{
mx[x]=x;
if (val[mx[ch[x][0]]]>val[mx[x]]) mx[x]=mx[ch[x][0]];
if (val[mx[ch[x][1]]]>val[mx[x]]) mx[x]=mx[ch[x][1]];
} void pushdown(int x)
{
if (rev[x])
{
rev[x]^=1;
rev[ch[x][0]]^=1;
rev[ch[x][1]]^=1;
swap(ch[x][0],ch[x][1]);
}
} void rot(int x)
{
int y=fa[x],z=fa[y],l,r;
if (ch[y][0]==x) l=0; else l=1;
r=l^1;
if (!isroot(y))
{
if (ch[z][0]==y) ch[z][0]=x;
else ch[z][1]=x;
}
fa[x]=z; fa[y]=x; fa[ch[x][r]]=y;
ch[y][l]=ch[x][r]; ch[x][r]=y;
update(y);update(x);
} void splay(int x)
{
top=0;sta[++top]=x;
for (int i=x;!isroot(i);i=fa[i]) sta[++top]=fa[i];
while (top) pushdown(sta[top--]); while (!isroot(x))
{
int y=fa[x],z=fa[y];
if (!isroot(y))
{
if (ch[y][0]==x^ch[z][0]==y) rot(y);
else rot(x);
}
rot(x);
}
} void access(int x)
{
for (int t=0;x;t=x,x=fa[x])
splay(x),ch[x][1]=t,update(x);
} void makeroot(int x)
{
access(x);
splay(x);
rev[x]^=1;
} int find(int x)
{
access(x);
splay(x);
while (ch[x][0]) x=ch[x][0];
return x;
} void link(int x,int y)
{
makeroot(x);
fa[x]=y;
} void cut(int x,int y)
{
makeroot(x);
access(y);
splay(y);
if (ch[y][0]==x)
{
ch[y][0]=x;
fa[x]=0;
}
} int query(int x,int y)
{
makeroot(x);
access(y);
splay(y);
return mx[y];
} int main()
{
Finout();
val[0]=-inf;
n=Getint();m=Getint();
F(i,1,n) val[i]=-inf;
F(i,1,m)
{
e[i].u=Getint();
e[i].v=Getint();
e[i].a=Getint();
e[i].b=Getint();
}
sort(e+1,e+m+1,cmp);
F(i,1,m)
{
int l=e[i].u,r=e[i].v,a=e[i].a,b=e[i].b;
int flag=0;
// cout<<l<<" "<<r<<" "<<a<<" "<<b<<endl;
if (find(l)==find(r))
{
int tmp=query(l,r);
if (val[tmp]>b)
{
// cout<<"cut "<<tmp<<" "<<e[tmp-n].v<<" "<<e[tmp-n].u<<endl;
cut(tmp,e[tmp-n].v);
cut(tmp,e[tmp-n].u);
flag=1;
}
else
{
// cout<<"cal"<<endl;
if (find(1)==find(n))
{
ans=min(ans,a+val[query(1,n)]);
continue;
}
}
}
else flag=1;
if (flag)
{
// cout<<"link"<<endl;
link(l,n+i);link(r,n+i);
val[n+i]=e[i].b;
mx[n+i]=n+i;
}
if (find(1)==find(n))
{
// cout<<"cal"<<endl;
ans=min(ans,a+val[query(1,n)]);
}
}
if (ans==inf) cout<<"-1"<<endl;
else cout<<ans<<endl;
}

  

BZOJ 3669 [Noi2014]魔法森林 ——SPFA / Link-Cut Tree的更多相关文章

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

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

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

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

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

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

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

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

  5. bzoj 3669: [Noi2014]魔法森林 动态树

    3669: [Noi2014]魔法森林 Time Limit: 30 Sec  Memory Limit: 512 MBSubmit: 363  Solved: 202[Submit][Status] ...

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

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

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

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

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

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

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

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

随机推荐

  1. JS 字符串 时间 数字函数操作 事件

    字符串  操作 var s="abcdefg" s.tolowerCase()   转小写 s.toupperCase()   转大写 s.substring(2,5)   索引下 ...

  2. sqlserver 视图用 case when

    视图用 case when 需要 用如下格式,[需要的列名]= case when...,而表里面的case 不用这样 [isNormal]=CASE WHENdbo.c_bdm_head.I_E_F ...

  3. 洛谷 P2292 [HNOI2004]L语言

    题目描述 标点符号的出现晚于文字的出现,所以以前的语言都是没有标点的.现在你要处理的就是一段没有标点的文章. 一段文章T是由若干小写字母构成.一个单词W也是由若干小写字母构成.一个字典D是若干个单词的 ...

  4. SAP Cloud for Customer使用移动设备访问系统的硬件要求

    如果用平板电脑的话,推荐的设备列表: Android Samsung Galaxy Tab S2○ Processor: 2 x quad-core CPU -- 1.9 and 1.3 gigahe ...

  5. 快学UiAutomator各种框架介绍

    Monkey 编写语言:命令行 运行环境:使用adb连接PC运行测试对象:Android平台自动化测试的一种手段,通过Monkey程序模拟用户触摸屏幕.滑动Trackball.按键等操作来对设备上的程 ...

  6. Linux关于FTP安全

    https://www.cnblogs.com/Hyber/archive/2017/02/04/6362916.htmlhttps://www.cnblogs.com/ichunqiu/p/7300 ...

  7. ios之UILabel

    详细使用: UILabel *label = [[UILabelalloc] initWithFrame:CGRectMake(0, 0, 75, 40)];   //声明UIlbel并指定其位置和长 ...

  8. ios 团购信息客户端demo(二)

    接上一篇,这篇我们对我们的客户端加入KissXML,MBProgressHUD,AQridView这几个库,首先我们先加入KissXML,这是XML解析库,支持Xpath,可以方便添加更改任何节点.先 ...

  9. Hdu 3177 (贪心)

    题目大意: 山洞的体积为\(v\) 第\(i\)个物品放在山洞里会占据\(a_i\)的空间,在搬运过程中至少需要\(b_i\)的空间 问能不能把所有物品都放下 贪心题.比较难看出贪心,但是从无顺序要求 ...

  10. lsof指令使用简介

    lsof替代了netstat和ps的全部工作.它可以带来那些工具所能带来的一切,而且要比那些工具多得多 最重要的是,当你给它传递选项时,默认行为是对结果进行“或”运算.因此,如果是用-i来拉出一个端口 ...