洛谷 P6822 - [PA2012]Tax(点转边+最短路)
作者:互联网
套路题一道。
首先直接抛出建图方式:
-
边化点,点转边。将每一条无向边 \(e=(u,v,w)\) 拆成一正一反两条有向边 \(e_1,e_2\),然后在 \(e_1,e_2\) 之间连权值为 \(w\) 的边。
-
对于每个点,将所有与其相连的边按权值从小到大排序,然后对于权值相邻的两条边 \((e_1,w_1),(e_2,w_2)(w_1<w_2)\),连边 \(e_1\to e_2\),权值 \(w_2-w_1\),以及 \(e_2\to e_1\),权值 \(0\)。
-
新建起点 \(S\) 和终点 \(T\),对于一条边,如果起点为 \(1\) 则从 \(S\) 向这条边连权值为这条边权值的边;如果终点为 \(n\) 则从这条边向 \(T\) 连权值为这条边权值的边。
然后跑 \(S\) 到 \(T\) 的最短路即可。
为什么?考虑将原图中一条路径对应到我们建出来的图中,假设这条路径为 \(1=p_1\to p_2\to p_3\to\cdots\to p_k=n\),经过的边分别为 \(e_1,e_2,\cdots,e_{k-1}\),那么对应到我们建出来的这张图中,这条路径映射到的路径就是 \(S\to e_1\to e_1\text{的反向边}\to e_2\to e_2\text{的反向边}\to\cdots\to e_{k-1}\to T\)。\(1,n\) 的贡献分别在 \(S\to e_1,e_{k-1}\to T\) 这两条边中体现,而对于一个非起点也非终点的 \(p_i\),如果前一条边 \(e_i\) 的权值 \(>e_{i+1}\) 的权值,那么在经过 \(e_i\to e_i\text{的反向边}\) 这条边后,必然会沿着 \(0\) 权边走到 \(e_{i+1}\),此时这个点的贡献就是 \(e_i\) 的权值,反之在经过 \(e_i\to e_i\text{的反向边}\) 这条边后,必然会沿着总权值为 \(e_{i+1}-e_i\) 的边走到 \(e_{i+1}\),此时这个点的贡献就是 \(e_{i+1}\) 的权值,因此在新图中我们映射到的路径的权值就是原图中这条路径的答案。
时间复杂度 \(m\log m\)。
const int MAXN = 1e5;
const int MAXM = 2e5;
int n, m;
int hd[MAXM * 2 + 5], nxt[MAXM * 10 + 5], val[MAXM * 10 + 5], to[MAXM * 10 + 5], ec = 0;
void adde(int u, int v, int w) {
// printf("adde %d %d %d\n", u, v, w);
to[++ec] = v; val[ec] = w;nxt[ec] = hd[u]; hd[u] = ec;
}
struct edge {
int u, v, w, id;
friend bool operator < (const edge &X, const edge &Y) {
return X.w < Y.w;
}
};
vector<edge> g[MAXN + 5];
ll dis[MAXM * 2 + 5];
int main() {
scanf("%d%d", &n, &m);
for (int i = 1, u, v, w; i <= m; i++) {
scanf("%d%d%d", &u, &v, &w);
g[u].pb({u, v, w, i << 1});
g[v].pb({v, u, w, i << 1 | 1});
adde(i << 1, i << 1 | 1, w);
adde(i << 1 | 1, i << 1, w);
}
for (int i = 1; i <= n; i++) {
sort(g[i].begin(), g[i].end());
for (int j = 1; j < g[i].size(); j++) {
adde(g[i][j].id, g[i][j - 1].id, 0);
adde(g[i][j - 1].id, g[i][j].id, g[i][j].w - g[i][j - 1].w);
}
if (i == 1) for (int j = 0; j < g[i].size(); j++) adde(0, g[i][j].id, g[i][j].w);
if (i == n) for (int j = 0; j < g[i].size(); j++) adde(g[i][j].id ^ 1, 1, g[i][j].w);
}
memset(dis, 63, sizeof(dis)); dis[0] = 0;
priority_queue<pair<ll, int>, vector<pair<ll, int> >, greater<pair<ll, int> > > q;
q.push(mp(0, 0));
while (!q.empty()) {
auto p = q.top(); q.pop(); int x = p.se;
for (int e = hd[x]; e; e = nxt[e]) {
int y = to[e], z = val[e];
if (dis[y] > dis[x] + z) {
dis[y] = dis[x] + z;
q.push(mp(dis[y], y));
}
}
}
printf("%lld\n", dis[1]);
return 0;
}
标签:洛谷,int,PA2012,MAXM,Tax,ec,权值,const,dis 来源: https://www.cnblogs.com/ET2006/p/luogu-P6822.html