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同学在号节 ...
随机推荐
- Power BI 连接到 Azure 账单,自动生成报表,可刷新
开始研究Azure官网等,提供的链接都是错误的,躺了很大的一个坑,配置后根本无法获取账单信息,经过多次查询找到了方向,过来记录一下: 错误的地址(应该是适用于全球版,国内版无法这样获取): https ...
- xp密钥
Windows XP 专业版 : CCC64-69Q48-Y3KWW-8V9GV-TVKRM
- Selenium私房菜系列9 -- Selenium RC服务器命令行参数列表【ZZ】
本文转载自:http://wiki.javascud.org/display/SEL/Selenium+Remote+Control+-+options 使用示例: java -jar seleniu ...
- codevs 1131 统计单词数 2011年NOIP全国联赛普及组
时间限制: 1 s 空间限制: 128000 KB 题目等级 : 白银 Silver 题目描述 Description 一般的文本编辑器都有查找单词的功能,该功能可以快速定位特定单词在文章中的位 ...
- 如何解决源码安装软件中make时一直重复打印configure信息
在通过源码安装软件时,会出现执行./configure后再make时总是重复打印configure的信息,无法进入下一阶段的安装. 主要原因是系统当前的时间与实际时间不一致,特别是在虚拟机上经常会出现 ...
- 算法马拉松13 A-E解题报告
A题意(取余最长路): 佳佳有一个n*m的带权矩阵,她想从(1,1)出发走到(n,m)且只能往右往下移动,她能得到的娱乐值为所经过的位置的权的总和. 有一天,她被下了恶毒的诅咒,这个诅咒的作用是将她的 ...
- python之路——目录
目录 python基础部分 基础部分 介绍.基本语法.流程控制 列表 元祖 字符串 字典 集合 文件操作 函数 变量 递归 迭代器,生成器,装饰器,Json和pickle 数据序列化 函数 初识函数 ...
- Windows server 2012安装oracle11g(32/64位)步骤
Oracle官方下地址: http://www.oracle.com/technetwork/database/enterprise-edition/downloads/index.html以下两网址 ...
- monkeyrunner之控件ID不存在或重复(转载lynnLi)
我们在用monkeyrunner进行Android自动化时,通过获取坐标点或控件ID进行一系列操作.由于使用坐标点时,屏幕分辨率一旦更改,则代码中用到坐标的地方都要修改,这样导致代码的复用率较低.因此 ...
- 服务器配置iis,php网站
1.在iis中选择物理路径.配置域名 2.添加php默认文档 3.修改处理程序映射 4.设置模块映射信息