[ARC061C] すぬけ君の地下鉄旅行 / Snuke's Subway Trip
阿新 • • 發佈:2020-12-14
這題應該有好多種建圖方法吧?這種方法與其他題解都不一樣。
一個套路的建圖方法,做過這題就很容易想到。
感覺這種題解不是很好寫,那就直接寫怎麼建圖然後講每一種邊的意義吧。
【建點】把邊當成點,正向邊和反向邊分別建點,再建立超級源點 \(S\) ,超級匯點 \(T\)
對於每一個節點 \(u\) 按照 \(v\) 顏色的顏色從小到大排序(我習慣把邊設成 \(u\to v\))。這樣所有起點為 \(u\) ,終點顏色相同的點會相鄰。
【邊一】如果這條邊的終點是 \(n\) ,那麼拉邊 \((id,T,0)\) ,因為它可以直接連到 \(n\)。
【邊二】如果這條邊的起點是 \(1\)
【邊三】對於 \(u\) 相同的兩個相鄰的出邊終點 \(v_1,v_2\) (邊的編號為 \(id_1,id_2\)),如果顏色相同,那麼拉邊 \((id_1,id_2,0),(id_2,id_1,0)\) ,因為這兩條邊可以免費走。【邊五】會講如果不同怎麼拉邊。
【邊四】正向邊向反向邊拉邊,因為走過去再走回來也可以。
我感覺剩下這種邊是這種建圖方法唯一的難點。
【邊五】我們現在還沒有處理顏色轉換的邊。這個東西看著賊難搞,不同顏色暴力拉邊的話複雜度就又可以被卡成平方了。
換個思路,新建一個虛點 \(x\)
往虛點走就意味著要換顏色,否則根本不會走長度為 \(1\) 的邊。而每一個顏色內部是可以隨便走的,所以這種建圖方法是對的。
總點數為 \(2m+n\) ,不要開小。還有顏色值域上限是 \(10^6\) ,不要開小了。
可以發現邊權只有 \(0\) 和 \(1\) ,直接bfs就可以 \(O(n)\) ,我偷懶寫了dij。
#include<bits/stdc++.h> using namespace std; #define fi first #define se second #define mkp(x,y) make_pair(x,y) #define pb(x) push_back(x) #define sz(v) (int)v.size() typedef long long LL; typedef double db; template<class T>bool ckmax(T&x,T y){return x<y?x=y,1:0;} template<class T>bool ckmin(T&x,T y){return x>y?x=y,1:0;} #define rep(i,x,y) for(int i=x,i##end=y;i<=i##end;++i) #define per(i,x,y) for(int i=x,i##end=y;i>=i##end;--i) inline int read(){ int x=0,f=1;char ch=getchar(); while(!isdigit(ch)){if(ch=='-')f=0;ch=getchar();} while(isdigit(ch))x=x*10+ch-'0',ch=getchar(); return f?x:-x; } const int N = 500005; const int C = 1000005; const int inf=0x3f3f3f3f; int n, m, S, T, tot; int dis[N]; bool vis[N]; struct node{ int w, v, id; node(){w = v = id = 0;} node(int w_, int v_, int id_) {w = w_, v = v_, id = id_;} inline bool operator < (const node&t) const {return w < t.w;} }; vector <node> E[N]; vector <pair<int, int> > e[N]; void Dij(){ priority_queue <pair<int,int> > pq; memset(dis, 0x3f, sizeof(dis)); pq.push(mkp(dis[S]=0, S)); while (!pq.empty()){ int u = pq.top().se; pq.pop(); if (vis[u]) continue; vis[u] = 1; for (int i = 0, up = sz(e[u]); i < up; ++ i){ int v = e[u][i].se; if (ckmin(dis[v] , dis[u] + e[u][i].fi)) if(!vis[v]) pq.push(mkp(-dis[v], v)); } } } signed main() { n = read(), m = read(), S = m * 2 + 2, T = tot = S + 1; rep(i, 1, m) { int x = read(), y = read(), z = read(); E[x].pb(node(z, y, i << 1)),E[y].pb(node(z, x, i << 1 | 1)); } rep(i, 1, n){ static int tag[C]; sort(E[i].begin(), E[i].end()), ++tot; for (int j = 0, up = sz(E[i]); j < up; ++ j){ node now = E[i][j]; if(tag[now.w]!=i){ tag[now.w]=i; e[now.id].pb(mkp(1, tot)); e[tot].pb(mkp(0, now.id)); } e[now.id].pb(mkp(0,now.id ^ 1)); if (i == 1) e[S].pb(mkp(1, now.id)); if (now.v == n) e[now.id].pb(mkp(0, T)); if (j && now.w == E[i][j-1].w) e[E[i][j-1].id].pb(mkp(0, now.id)), e[now.id].pb(mkp(0, E[i][j-1].id)); } } Dij(), printf("%d\n", dis[T] == inf ? -1 : dis[T]); return 0; }