[BZOJ4289] [PA2012] Tax 解题报告 (最短路+差分建图)
题目链接:https://www.lydsy.com/JudgeOnline/problem.php?id=4289
4289: PA2012 Tax
Time Limit: 10 Sec Memory Limit: 128 MB
Submit: 1029 Solved: 310
[Submit][Status][Discuss]
Description
Sample Input
1 2 5
1 3 2
2 3 1
2 4 4
3 4 8
Sample Output
12
比较有技巧的建图
首先考虑暴力点的建图:
把每条无向边拆成两条有向边.把每条边看成一个点,对于两条边a->b,b->c
在这两条边之间连有向边,边权为这两条边的权值的较大值.
新建源点S,汇点T, S向所有从1连出去的边连边,所有指向n的边向T连边. 求S->T的最短路即可.
这样的复杂度会达到O(m2)
考虑优化一下:
考虑利用差值来建边.
依然把每条边x-y拆成x->y,y->x.
枚举每个中转点x. 将x的出边按权值排序,x的每条入边向对应的出边连该边权值的边(i对应i^1)),x的每条出边向第一个比它大的出边连两边权差值的边,x的每条出边向第一个比它小的出边连权值为0的边. 新建源汇S,T S向每条1的出边连权值为该边边权的边.每条n的入边向T连该边权值的边.

仔细看图,L2>L1,发现从S到T的路径走的一定是L2,而不是L1;注意结合上述的建图过程(红色边)
跑S->T的最短路即可.
这样的复杂度是O(mlogm)就可以AC
我的SPFA被T了,估计没写错只是被卡了
以上内容部分参考DaD3zZ大佬的博客
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<queue>
#define ll long long
using namespace std; const int N=+;
int n,m,tot1,tot2,S,T;
int head[N],h[N<<],st[N<<],vis[N<<];
ll dist[N<<];
struct EDGE
{
int to;int next;int l;
}edge[N<<],e[N<<];
inline int read()
{
char ch=getchar();
int s=,f=;
while (!(ch>=''&&ch<='')) {if (ch=='-') f=-;ch=getchar();}
while (ch>=''&&ch<='') {s=(s<<)+(s<<)+ch-'';ch=getchar();}
return s*f;
}
void init()
{
memset(head,-,sizeof(head));
memset(h,-,sizeof(h));
memset(dist,0x3f3f3f3f,sizeof(dist));
}
void addedge(int x,int y,int l)
{
edge[tot1]=(EDGE){y,head[x],l};
head[x]=tot1++;
}
bool cmp(int x,int y) {return edge[x].l<edge[y].l;}
void addroad(int x,int y,int l)
{
e[tot2]=(EDGE){y,h[x],l};
h[x]=tot2++;
}
void build()
{
S=*(m+)+;T=*(m+)+;
for (int i=;i<=n;i++)
{
int tp=;
for (int j=head[i];j!=-;j=edge[j].next)
st[++tp]=j;
sort(st+,st++tp,cmp);
for (int j=;j<=tp;j++)
{
int now=st[j],suc=st[j+];
if (edge[now].to==n) addroad(now,T,edge[now].l);
if (i==) addroad(S,now,edge[now].l);
addroad(now^,now,edge[now].l);
if (j<tp) {addroad(now,suc,edge[suc].l-edge[now].l);addroad(suc,now,);}
}
}
}
priority_queue<pair<ll,int>,vector<pair<ll,int> >,greater<pair<ll,int> > > q;
void Dijkstra()
{
q.push(make_pair(,S));
dist[S]=;
while (!q.empty())
{
int now=q.top().second;
ll Dis=q.top().first;q.pop();
if (Dis>dist[now]) continue;
for (int i=h[now];i!=-;i=e[i].next)
if (dist[now]+e[i].l<dist[e[i].to])
{
dist[e[i].to]=dist[now]+e[i].l;
q.push(make_pair(dist[e[i].to],e[i].to));
}
}
}
int main()
{
n=read();m=read();
init();
for (int i=;i<=m;i++)
{
int x=read(),y=read(),l=read();
addedge(x,y,l);addedge(y,x,l);
}
build();
Dijkstra();
printf("%lld\n",dist[T]);
return ;
}
[BZOJ4289] [PA2012] Tax 解题报告 (最短路+差分建图)的更多相关文章
- BZOJ 4289: PA2012 Tax 差分建图 最短路
https://www.lydsy.com/JudgeOnline/problem.php?id=4289 https://www.cnblogs.com/clrs97/p/5046933.html ...
- 【BZOJ-4289】Tax 最短路 + 技巧建图
4289: PA2012 Tax Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 168 Solved: 69[Submit][Status][Dis ...
- [Bzoj4289]PA2012 Tax(Dijkstra+技巧建图)
Description 给出一个N个点M条边的无向图,经过一个点的代价是进入和离开这个点的两条边的边权的较大值,求从起点1到点N的最小代价.起点的代价是离开起点的边的边权,终点的代价是进入终点的边的边 ...
- 【BZOJ-4289】Tax 最短路 + 技巧建图(化边为点)
题意 给出一个N个点M条边的无向图,经过一个点的代价是进入和离开这个点的两条边的边权的较大值,求从起点1到点N的最小代价.起点的代价是离开起点的边的边权,终点的代价是进入终点的边的边权N<=10 ...
- LOJ#6354. 「CodePlus 2018 4 月赛」最短路[最短路优化建图]
题意 一个 \(n\) 个点的完全图,两点之间的边权为 \((i\ xor\ j)*C\) ,同时有 \(m\) 条额外单向路径,问从 \(S\) 到 \(T\) 的最短路. \(n\leq 10^5 ...
- [BZOJ4289][PA2012]TAX(最短路)
首先考虑一种暴力做法,为每条边拆成两条有向边,各建一个点.若某两条边有公共点,则在边所对应的点之间连一条边,权值为两条边中的较大值.这样跑最短路是$O(m^2\log m)$的. 用类似网络流中补流的 ...
- BZOJ4289 : PA2012 Tax
一个直观的想法是把每条边拆成两条有向边,同时每条有向边是新图中的一个点.对于两条边a->b与b->c,两点之间连有向边,费用为两条边费用的最大值.然后新建源点S与汇点T,由S向所有起点为1 ...
- bzoj4289 PA2012 Tax——点边转化
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=4289 好巧妙的转化!感觉自己难以想出来... 参考了博客:https://blog.csdn ...
- 灯光照射,圆形探测类问题(解题报告)<分层差分><cmath取整>
题目描述 一个n*n的网格图上有m个探测器,每个探测器有个探测半径r,问这n*n个点中有多少个点能被探测到. 输入输出格式 输入格式: (1<=r<n<=5000) (1<=m ...
随机推荐
- Html 播放 mp4格式视频提示 没有发现支持的视频格式和mime类型
转自原文 Html 播放 mp4格式视频提示 没有发现支持的视频格式和mime类型 播放mp4格式的时候提示 Html 播放 mp4格式视频提示 没有发现支持的视频格式和mime类型 原因是在IIS中 ...
- csdn第五届在线编程大赛-全然平方
题目详情 给定整数区间[A,B]问当中有多少个全然平方数. 输入格式: 多组数据,包括两个正整数A,B 1<=A<=B<=2000000000. 输出格式: 每组数据输出一行包括一个 ...
- 上机题目(0基础)-计算两个正整数的最大公约数和最小公倍数(Java)
题目例如以下:
- C++链接和执行相关错误
http://blog.csdn.net/pipisorry/article/details/37610401 LINK : fatal error LNK1123: 转换到 COFF 期间失败: 文 ...
- Woody的Python学习笔记2
Python多行语句 Python语句中一般以新行作为语句的结束符.但我们能够使用斜杠(\)将一行的语句分为多行显示,例如以下所看到的: total = item_one+\ item_two + \ ...
- Android使用有道翻译API实如今线翻译功能
在Android应用中,加入在线翻译的功能,这里调用的是有道翻译的API. 使用有道翻译API.首先要申请一个key,申请地址为:path=data-mode">有道翻译API申请地址 ...
- "浪潮杯"第六届ACM山东省省赛山科场总结
从空间拷过来的.尽管已经过去一个月了.记忆犹新 也算是又一次拾起这个blog Just begin 看着一群群大牛还有队友男神的省赛总结都出了 我最终也耐不住寂寞 来做个流水账抒抒情好了 第一次省赛 ...
- ubuntu 交叉编译qt 5.7 程序到 arm 开发板
ubuntu 交叉编译qt 5.7 程序到 arm 开发板平台1 ubuntu 12.042 arm-linux-gcc 4.5.13 QT 5.74 开发板210 armcortex-A8 一 概述 ...
- KMP字符串查找算法
#include <iostream> #include <windows.h> using namespace std; void get_next(char *str,in ...
- shell-3.bash的基本功能:多命令顺序执行与管道符
1. 2.