luogu P6822 [PA2012]Tax
https://www.luogu.com.cn/problem/P6822
是个NB套路题
首先把无向边变成两条有项边
然后边变成点,
新建一个超级起始点和终点
对于原图连向
1
1
1的点,全部连向超级起始点,连向
n
n
n的连向超级终点
对于每条边,连向自己的反向边,权值为边权大小
然后对于原图的每个点,把和它相连的边排个序,然后前一条边连向后一条边,边权为两边权值的差
这样跑出来的就是答案了
code:
#include<bits/stdc++.h>
#define N 400050
#define ll long long
using namespace std;
struct edge {
int v, nxt; ll c;
} e[N << 2];
int p[N], eid;
void init() {
memset(p, -1, sizeof p);
eid = 0;
}
void insert(int u, int v, int c) { //printf("%d --> %d %d\n", u, v, c);
e[eid].v = v;
e[eid].c = c;
e[eid].nxt = p[u];
p[u] = eid ++;
}
struct A {
ll dis; int id;
bool operator < (const A &o) const {
return dis > o.dis;
}
};
priority_queue<A> q;
int vis[N], S, T;
ll dis[N];
void dij() {
memset(dis, 0x3f, sizeof dis);
dis[S] = 0, q.push((A){0, S});
while(q.size()) {
int u = q.top().id; q.pop();
if(vis[u]) continue;
vis[u] = 1;
for(int i = p[u]; i + 1; i = e[i].nxt) {
int v = e[i].v; ll c = e[i].c;
if(dis[v] > dis[u] + c) {
dis[v] = dis[u] + c;
q.push((A){dis[v], v});
}
}
}
// for(int i = 1; i <= T; i ++) printf("%lld ", dis[i]); printf(" *\n");
}
struct G {
int v, c, id;
bool operator < (const G &o) const {
return c < o.c;
}
};
vector<G> g[N];
int n, m;
int main() {
init();
scanf("%d%d", &n, &m);
for(int i = 1; i <= m; i ++) {
int u, v, c;
scanf("%d%d%d", &u, &v, &c);
g[u].push_back((G){v, c, i << 1});
g[v].push_back((G){u, c, i << 1 | 1});
}
//S = 0, T = 1;
S = m * 2 + 3, T = S + 1;
for(int u = 1; u <= n; u ++) {
sort(g[u].begin(), g[u].end());
for(int i = 0; i < g[u].size(); i ++) {
int v = g[u][i].v, id = g[u][i].id, c = g[u][i].c;
insert(id ^ 1, id, c);
if(u == 1) insert(S, id, c);
if(v == n) insert(id, T, c);
}
for(int i = 1; i < g[u].size(); i ++) {
int v = g[u][i].v, id = g[u][i].id, c = g[u][i].c;
insert(id, g[u][i - 1].id, 0);
insert(g[u][i - 1].id, id, c - g[u][i - 1].c);
}
}
dij();
printf("%lld", dis[T]);
return 0;
}