【BZOJ-4289】Tax 最短路 + 技巧建图

4289: PA2012 Tax

Time Limit: 10 Sec  Memory Limit: 128 MB
Submit: 168  Solved: 69
[Submit][Status][Discuss]

Description

给出一个N个点M条边的无向图,经过一个点的代价是进入和离开这个点的两条边的边权的较大值,求从起点1到点N的最小代价。起点的代价是离开起点的边的边权,终点的代价是进入终点的边的边权

N<=100000

M<=200000

Input

Output

Sample Input

4 5
1 2 5
1 3 2
2 3 1
2 4 4
3 4 8

Sample Output

12

HINT

Source

Solution

比较有技巧的建图

首先考虑暴力点的建图:

把每条无向边拆成两条有向边.把每条边看成一个点,对于两条边a->b,b->c

在这两条边之间连有向边,边权为这两条边的权值的较大值.

新建源点S,汇点T, S向所有从1连出去的边连边,所有指向n的边向T连边. 求S->T的最短路即可.

这样的复杂度会达到$O(m^{2})$

考虑优化一下,有个类似网络流中补流思想的方法:

考虑利用差值来建边.

依然把每条边x-y拆成x->y,y->x.

枚举每个中转点x. 将x的出边按权值排序,x的每条入边向对应的出边连该边权值的边,x的每条出边向第一个比它大的出边连两边权差值的边,x的每条出边向第一个比它小的出边连权值为0的边. 新建源汇S,T S向每条1的出边连权值为该边边权的边.每条n的入边向T连该边权值的边.

跑S->T的最短路即可.

这样的复杂度是$O(mlogm)$就可以AC

顺带提一句,用Dijkstra效率很快

Code

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<queue>
using namespace std;
void Freopen() {freopen("travel.in","r",stdin); freopen("travel.out","w",stdout);}
#define Pa pair<long long,int>
inline int read()
{
    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;
}
#define MAXN 200010
#define INF 1LL<<60
int N,M;
struct EdgeNode{int next,to,val;}edge[MAXN<<1],road[MAXN<<3];
int head[MAXN],cnt=1,first[MAXN<<1],tot=1;
inline void AddEdge(int u,int v,int w) {cnt++; edge[cnt].next=head[u]; head[u]=cnt; edge[cnt].to=v; edge[cnt].val=w;}
inline void InsertEdge(int u,int v,int w) {AddEdge(u,v,w); AddEdge(v,u,w);}
inline void AddRoad(int u,int v,int w) {tot++; road[tot].next=first[u]; first[u]=tot; road[tot].to=v; road[tot].val=w;}
inline bool cmp(int x,int y) {return edge[x].val<edge[y].val;}
priority_queue<Pa,vector<Pa>,greater<Pa> >q;
int S,T;
long long dis[MAXN<<1];
void Dijkstra()
{
    for (int i=S; i<=T; i++) dis[i]=INF;
    q.push(make_pair(0,S)); dis[S]=0;
    while (!q.empty())
        {
            int now=q.top().second;
            long long Dis=q.top().first;
            q.pop();
            if (Dis>dis[now]) continue;
            for (int i=first[now]; i; i=road[i].next)
                if (dis[now]+road[i].val<dis[road[i].to])
                    dis[road[i].to]=dis[now]+road[i].val,
                    q.push(make_pair(dis[road[i].to],road[i].to));
        }
}
int st[MAXN<<1],tp;
void BuildGraph()
{
    S=1,T=2*(M+1);
    for (int i=1; i<=N; i++)
        {
            tp=0;
            for (int j=head[i]; j; j=edge[j].next)
                st[++tp]=j;
            sort(st+1,st+tp+1,cmp);
            for (int j=1; j<=tp; j++)
                {
                    int now=st[j],suc=st[j+1];
                    if (edge[now].to==N) AddRoad(now,T,edge[now].val);
                    if (i==1) AddRoad(S,now,edge[now].val);
                    AddRoad(now^1,now,edge[now].val);
                    if (j<tp) AddRoad(now,suc,edge[suc].val-edge[now].val),AddRoad(suc,now,0);
                }
        }
}
int main()
{
//  Freopen();
    N=read(),M=read();
    for (int x,y,z,i=1; i<=M; i++) x=read(),y=read(),z=read(),InsertEdge(x,y,z);
    BuildGraph();
    Dijkstra();
    printf("%lld\n",dis[T]);
    return 0;
}

小压一波常数,成功跑到rank2..想怒压300ms到rank1时,失误反而慢了300ms....23333

Orz现场裸跑最短路80分的梁哥....

貌似还有一种类似于DP的方法?

时间: 2024-11-08 01:26:01

【BZOJ-4289】Tax 最短路 + 技巧建图的相关文章

【Bzoj4289】PA2012 Tax(Dijkstra+技巧建图)

Description 给出一个N个点M条边的无向图,经过一个点的代价是进入和离开这个点的两条边的边权的较大值,求从起点1到点N的最小代价.起点的代价是离开起点的边的边权,终点的代价是进入终点的边的边权 N<=100000 M<=200000 Solution 这题关键在于化边为点,把无向边拆成2条有向边 考虑最直白的一种建图方法,对于每一个点u,它的每一条入边向所有出边连边 但这样边数太多了,最坏是\(M^2\)条边,不可行 考虑用差值来建图,每条出边向第一条比它大的出边连一条权值为权差值的

bzoj 4289 Tax - 最短路

题目传送门 这是一条通往vjudge的神秘通道 这是一条通往bzoj的神秘通道 题目大意 如果一条路径走过的边依次为$e_{1}, e_{2}, \cdots , e_{k}$,那么它的长度为$e_{1} + \max (e_{1}, e_{2}) + \max (e_{2}, e_{3}) + \cdots + \max (e_{k - 1}, e_{k}) + e_{k}$,问点$1$到点$n$的最短路. 显然需要把状态记在最后一条边上. 然后给一个菊花图,这个做法就gg了. 因此考虑一些黑

POJ 2502 Subway (Dijkstra 最短路+建图)

Subway Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 6689   Accepted: 2176 Description You have just moved from a quiet Waterloo neighbourhood to a big, noisy city. Instead of getting to ride your bike to school every day, you now get

bzoj 2259 [Oibh]新型计算机 ——最短路(建图)

题目:https://www.lydsy.com/JudgeOnline/problem.php?id=2259 不是 n^2 条边!连那条边权为0的边之后,只要每个位置向它的前一个位置和后一个位置连 1 的边,就能等价于一开始就走到那个位置了. 不会有情况使得操作后 a[ i ] 变成负数来走到 j .因为那样一定不如走到 i 的时候别走到 i 而是直接走到 j . 注意1号点.如果每个点都向后连 1 的边,最大代价岂不是不大于 n ?所以 1 不能向 2 连边权为1的边,因为1是起点,没有转

bzoj 4289 TAX —— 点边转化

题目:https://www.lydsy.com/JudgeOnline/problem.php?id=4289 把边转化成点,同一个原有点相连的边中,边权小的向大的连差值的边,大的向小的连0的边: 一开始想的是给每个新点记一个点权是这个点(边)原来的权,走到它时先加上点权,因为要在原图上经过这条边还是要花费边权: 但是这样在原图中的边之间转移时会把它们的边权都加上,就不对了: 所以应该是把原图的边进一步拆成两个点,两端点的集合各加入一个,这两点之间连原边权的边: 题目上什么也没说...总之 d

Codeforces 787D. Legacy 线段树优化建图+最短路

output standard output Rick and his co-workers have made a new radioactive formula and a lot of bad guys are after them. So Rick wants to give his legacy to Morty before bad guys catch them. There are n planets in their universe numbered from 1 to n.

UESTC30-最短路-Floyd最短路、spfa+链式前向星建图

最短路 Time Limit: 3000/1000MS (Java/Others) Memory Limit: 65535/65535KB (Java/Others) 在每年的校赛里,所有进入决赛的同学都会获得一件很漂亮的T-shirt.但是每当我们的工作人员把上百件的衣服从商店运回到赛场的时候,却是非常累的!所以现在他们想要寻找最短的从商店到赛场的路线,你可以帮助他们吗? Input 输入包括多组数据. 每组数据第一行是两个整数NN ,MM (N≤100N≤100 ,M≤10000M≤1000

HDU5669 Road 分层最短路+线段树建图

分析:(官方题解) 首先考虑暴力,显然可以直接每次O(n^2) ?的连边,最后跑一次分层图最短路就行了. 然后我们考虑优化一下这个连边的过程 ,因为都是区间上的操作,所以能够很明显的想到利用线段树来维护整个图, 连边时候找到对应区间,把线段树的节点之间连边.这样可以大大缩减边的规模,然后再跑分层图最短路就可以了. 但是这样建图,每一次加边都要在O(logn)个线段树节点上加边,虽然跑的非常快,但是复杂度仍然是不科学的. 为了解决边的规模的问题,开两棵线段树,连边时候可以新建一个中间节点,在对应区

hdu 5294 Tricks Device 最短路建图+最小割

链接:http://acm.hdu.edu.cn/showproblem.php?pid=5294 Tricks Device Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others) Total Submission(s): 375    Accepted Submission(s): 98 Problem Description Innocent Wu follows Dumb Zh