[PA2012] Tax
Posted qixingzhi
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[PA2012] Tax相关的知识,希望对你有一定的参考价值。
传送门:>Here<
题意:给出一个N个点M条边的无向图,经过一个点的代价是进入和离开这个点的两条边的边权的较大值,求从起点1到点N的最小代价。起点的代价是离开起点的边的边权,终点的代价是进入终点的边的边权N<=100000 M<=200000
解题思路
不免要吐槽一下这题的数据,久调一下午无果与标程对拍没有任何差错不知道为什么就是WA 既然极限数据已经和标程拍上了那么权当出了吧……
不过还是一道好题
首先考虑这道题暴力的做法——将每条边作为新图的点,然后枚举原图的点,遍历一遍这个点相邻的所有边,按照大小打擂在新图中连边,但是这样边的数量多达$M^2$
可以考虑优化边的数量,用到差分的思想——以其中一条边作为基准,往上走要加,往下走不加。作为基准的这一条边也就是当前路径的入边,至于出边,只需要沿着差分的边走就可以了。于是我们所需要做的就是将每个点相邻的所有边排序,并且相邻的连边——大的往小的权值为0,小的往大的权值为差值。并且对于每一条边,它的反向边应当与它连一条权值为其本身的边,作为基准嘛
Code
/*By DennyQi 2018.8.11*/ #include <cstdio> #include <queue> #include <cstring> #include <algorithm> #define r read() #define lr lread() #define Max(a,b) (((a)>(b)) ? (a) : (b)) #define Min(a,b) (((a)<(b)) ? (a) : (b)) using namespace std; typedef long long ll; const int MAXN = 2000010; const int MAXM = 2000010; const int INF = 1e18; inline int read(){ int x = 0; int w = 1; register int c = getchar(); while(c ^ ‘-‘ && (c < ‘0‘ || c > ‘9‘)) c = getchar(); if(c == ‘-‘) w = -1, c = getchar(); while(c >= ‘0‘ && c <= ‘9‘) x = (x << 3) + (x << 1) + c - ‘0‘, c = getchar(); return x * w; } inline int lread(){ ll x = 0; int w = 1; register int c = getchar(); while(c ^ ‘-‘ && (c < ‘0‘ || c > ‘9‘)) c = getchar(); if(c == ‘-‘) w = -1, c = getchar(); while(c >= ‘0‘ && c <= ‘9‘) x = (x << 3) + (x << 1) + c - ‘0‘, c = getchar(); return x * w; } struct Edge{ ll len; int idx; }e[MAXM]; struct Dij{ ll w; int idx; }; inline bool operator < (const Dij& a, const Dij& b){ return a.w > b.w; } int N,M,x,y,S,T,v,top; int pfirst[MAXM],pnxt[MAXM],pto[MAXM],pnum_edge=-1; ll pcost[MAXM],cost[MAXM],z; int first[MAXM],nxt[MAXM],to[MAXM],num_edge=-1; ll d[MAXM]; bool vis[MAXM]; priority_queue <Dij> q; inline bool comp(const Edge& a, const Edge& b){ return a.len < b.len; } inline void add(int u, int v, int w){ // printf("%lld->%lld(%lld) ",u,v,w); to[++num_edge] = v; cost[num_edge] = w; nxt[num_edge] = first[u]; first[u] = num_edge; } inline void padd(int u, int v, int w){ pto[++pnum_edge] = v; // printf("num(%lld): %lld->%lld(%lld) ",pnum_edge,u,v,w); pcost[pnum_edge] = w; pnxt[pnum_edge] = pfirst[u]; pfirst[u] = pnum_edge; if(u == 1){ add(S, pnum_edge, w); } if(v == N){ add(pnum_edge, T, w); } } inline void Dijkstra(int s){ for(int i = 0; i <= T; ++i) d[i] = INF; d[s] = 0; q.push((Dij){0,s}); ll u,v; while(!q.empty()){ u = q.top().idx; q.pop(); if(vis[u]) continue; vis[u] = 1; for(int i = first[u]; i != -1; i = nxt[i]){ v = to[i]; if(d[u] + cost[i] < d[v]){ d[v] = d[u] + cost[i]; q.push((Dij){d[v],v}); } } } } int main(){ // freopen(".in","r",stdin); // freopen("qxz.out","w",stdout); N = r, M = r; memset(pfirst,-1,sizeof(pfirst)); memset(first,-1,sizeof(first)); S = M*2+1; T = M*2+2; // printf("S = %lld T = %lld ",S,T); for(int i = 1; i <= M; ++i){ x = r, y = r, z = lr; padd(x, y, z); padd(y, x, z); } int v; for(int x = 2; x < N; ++x){ top = 0; for(int i = pfirst[x]; i != -1; i = pnxt[i]){ e[++top] = (Edge){pcost[i], i}; } sort(e+1,e+top+1,comp); for(int i = 1; i <= top; ++i){ if(i < top){ add(e[i].idx, e[i+1].idx, e[i+1].len-e[i].len); } if(i > 1){ add(e[i].idx, e[i-1].idx, 0); } add(e[i].idx^1, e[i].idx, e[i].len); } } Dijkstra(S); printf("%lld", d[T]); return 0; }
以上是关于[PA2012] Tax的主要内容,如果未能解决你的问题,请参考以下文章
BZOJ.4289.PA2012 Tax(思路 Dijkstra)