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同学在号节 ...
随机推荐
- powershell 根据错误GUID查寻错误详情
使用azurepowershell 部署模板时,碰到了下面类似的问题: The template deployment 'ExampleDeployment-' is not valid accord ...
- COGS 788. 昵称
788. 昵称 ★☆ 输入文件:nickname.in 输出文件:nickname.out 简单对比时间限制:1 s 内存限制:128 MB [问题描述] ZSUQ送信者与腾讯QQ相似 ...
- iosopendev配置
Permission denied, please try again.Permission denied, please try again.Permission denied (publickey ...
- leetcode 127 单词接龙
给定两个单词(beginWord 和 endWord)和一个字典,找到从 beginWord 到 endWord 的最短转换序列的长度.转换需遵循如下规则: 每次转换只能改变一个字母. 转换过程中的中 ...
- 你是猴子请来的逗比么!IT跳槽大事件
3月招聘大战早已硝烟四起,互联网职场摇身一变成了跳蚤市场,猎头们告诉跳蚤们,跳不跳不是不问题,往哪儿跳才是重点,跳对了高薪期权都如过眼云烟.不过小编不得不说,劳资最痛恨那些跳槽的人啦!就因为加班 ...
- 由DAG到背包问题——记忆化搜索和递推两种解法
一.问题描述 物品无限的背包问题:有n种物品,每种均有无穷多个.第 i 种物品的体积为Vi,重量为Wi.选一些物品装到一个容量为 C 的背包中,求使得背包内物品总体积不超过C的前提下重量的最大值.1≤ ...
- urllib基础-请求对象request
简单的案例-爬取百度首页 from urllib import request ''' 爬取百度首页 ''' # 确定爬去目标 base_url = 'http://www.baidu.com' # ...
- 浏览器输入一个url到整个页面显示出来经历了哪些过程?
https://cloud.tencent.com/developer/article/1396399 https://www.cnblogs.com/haonanZhang/p/6362233.ht ...
- 测试框架 Mocha 实例教程(转载:来自阮一峰的一篇文章)
Mocha(发音"摩卡")诞生于2011年,是现在最流行的JavaScript测试框架之一,在浏览器和Node环境都可以使用. 所谓"测试框架",就是运行测试的 ...
- ios之UISearchBar
当你在seachBar中输入字母之前的时候,只是用鼠标选中searchBar的时候,如图 终端输出截图如下:(这个时候调用先shouldBeginEditing,之后调用didBeginEditing ...