BZOJ 3669 [Noi2014]魔法森林 ——SPFA / Link-Cut Tree
【题目分析】
大意就是有一张图,边权有两个值,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的更多相关文章
- bzoj 3669: [Noi2014]魔法森林
bzoj 3669: [Noi2014]魔法森林 Description 为了得到书法大家的真传,小E同学下定决心去拜访住在魔法森林中的隐士.魔法森林可以被看成一个包含个N节点M条边的无向图,节点标号 ...
- bzoj 3669: [Noi2014]魔法森林 -- 动点spfa
3669: [Noi2014]魔法森林 Time Limit: 30 Sec Memory Limit: 512 MB 动点spfa Description 为了得到书法大家的真传,小E同学下定决心 ...
- bzoj 3669: [Noi2014]魔法森林 (LCT)
链接:https://www.lydsy.com/JudgeOnline/problem.php?id=3669 题面: 3669: [Noi2014]魔法森林 Time Limit: 30 Sec ...
- BZOJ 3669: [Noi2014]魔法森林( LCT )
排序搞掉一维, 然后就用LCT维护加边MST. O(NlogN) ------------------------------------------------------------------- ...
- bzoj 3669: [Noi2014]魔法森林 动态树
3669: [Noi2014]魔法森林 Time Limit: 30 Sec Memory Limit: 512 MBSubmit: 363 Solved: 202[Submit][Status] ...
- BZOJ 3669: [Noi2014]魔法森林 [LCT Kruskal | SPFA]
题目描述 为了得到书法大家的真传,小 E 同学下定决心去拜访住在魔法森林中的隐 士.魔法森林可以被看成一个包含 n 个节点 m 条边的无向图,节点标号为 1,2,3,…,n,边标号为 1,2,3,…, ...
- [BZOJ 3669] [Noi2014] 魔法森林 【LCT】
题目链接:BZOJ - 3669 题目分析 如果确定了带 x 只精灵A,那么我们就是要找一条 1 到 n 的路径,满足只经过 Ai <= x 的边,而且要使经过的边中最大的 Bi 尽量小. 其实 ...
- 图论 BZOJ 3669 [Noi2014]魔法森林
Description 为了得到书法大家的真传,小E同学下定决心去拜访住在魔法森林中的隐士.魔法森林可以被看成一个包含个N节点M条边的无向图,节点标号为1..N,边标号为1..M.初始时小E同学在号节 ...
- bzoj 3669: [Noi2014] 魔法森林 LCT版
Description 为了得到书法大家的真传,小E同学下定决心去拜访住在魔法森林中的隐士.魔法森林可以被看成一个包含个N节点M条边的无向图,节点标号为1..N,边标号为1..M.初始时小E同学在号节 ...
随机推荐
- IT之家学院:使用CMD命令行满速下载百度云
转自:https://www.toutiao.com/a6545305189685920259/?tt_from=android_share&utm_campaign=client_share ...
- Mysql的Root密码忘记,查看或修改的解决方法
Mysql的Root密码忘记,查看或修改的解决方法:1.首先启动命令行2.在命令行运行:taskkill /f /im mysqld-nt.exe3.继续在命令行运行:mysqld-nt --skip ...
- 使用Google Colab训练神经网络(二)
Colaboratory 是一个 Google 研究项目,旨在帮助传播机器学习培训和研究成果.它是一个 Jupyter 笔记本环境,不需要进行任何设置就可以使用,并且完全在云端运行.Colaborat ...
- Gradle环境下导出Swagger为PDF
更多精彩博文,欢迎访问我的个人博客 说明 我个人是一直使用Swagger作为接口文档的说明的.但是由于在一些情况下,接口文档说明需要以文件的形式交付出去,如果再重新写一份文档难免有些麻烦.于是在网上看 ...
- 【转】将Eclipse中的CTRL+K搬到IDEA中
https://my.oschina.net/sprieo/blog/224838 IDEA的该功能是CTRL+F3,行为是获取当前光标位置的单词然后调用搜索.只需要按CTRL+F3一次,就可以实现C ...
- windows10锁定屏幕聚焦图片导出
打开运行,输入%LocalAppData%\Packages\Microsoft.Windows.ContentDeliveryManager_cw5n1h2txyewy\LocalState\Ass ...
- Luogu P4231 三步必杀 (差分)
目录 题目 题解 题目 题目链接 题目背景 (三)旧都 离开狭窄的洞穴,眼前豁然开朗. 天空飘着不寻常的雪花. 一反之前的幽闭,现在面对的,是繁华的街市,可以听见酒碗碰撞的声音. 这是由被人们厌恶的鬼 ...
- DP入门练习
T1 题目:codevs4815江哥的dp题a codevs4815 一个简单的DP,注意开long long(不然会全WA),以及初始条件(这题有负数,所以要把f设成极小值.还要保证转移正确). # ...
- virtualenvwrapper.sh报错: There was a problem running the initialization hooks.解决
由于在ubuntu环境下,将python做与python3.6做了软链接(ln -s python python3.6),并且pip也被我做了软链接,所以导致用pip安装virtualenvwrapp ...
- laravel 设计思想简单了解
服务容器 laravel框架中 服务容器是整个系统功能调度配置的核心,在系统运行过程中动态的为系统提供需要的服务 从而实现了解耦 控制反转(IOC) 控制反转是一种设计模式 主要解决了系统组件之间的相 ...