Legend
Link \(\textrm{to Codeforces}\)。
给定 \(n\ (1 \le 500\ 000)\) 个点,\(m \ (0 \le m \le 500\ 000)\) 条有向边,每条边为两种颜色之一。
你需要给点染色,点染色后只能走颜色相同的出边。找到一种染色方案使得 \(1\to n\) 最短路最长。
Editorial
这题很容易让人想成 \(\textrm{dp}\)。
你发现设 \(\textrm{dp}\) 的时候总是想带着一个维度:点的颜色。
点的颜色真的这么恶心吗?
算是个套路吧,建一个反图,那么这条边和它的终点的颜色就会是相同的,我们就不需要理会点的颜色了。
我们把每一个点 \(\textrm{bfs}\) 到第二种不同的颜色的时候才更新路径长度即可。
Code
#include <bits/stdc++.h>
using namespace std;
const int MX = 5e5 + 233;
int head[MX] ,tot;
struct edge{int node ,next ,w;}h[MX];
void addedge(int u ,int v ,int w){h[++tot] = (edge){v ,head[u] ,w} ,head[u] = tot;}
int vis[MX] ,color[MX];
int dis[MX] ,n ,m;
void bfs(){
queue<int> q;
q.push(n);
dis[1] = -1;
dis[n] = 0;
while(!q.empty()){
int x = q.front(); q.pop();
for(int i = head[x] ,d ; i ; i = h[i].next){
d = h[i].node;
if(vis[d] == 3) continue;
vis[d] |= 1 << h[i].w;
if(vis[d] == 3){
q.push(d);
dis[d] = dis[x] + 1;
}else{
color[d] = h[i].w ^ 1;
}
}
}
}
int read(){
char k = getchar(); int x = 0;
while(k < '0' || k > '9') k = getchar();
while(k >= '0' && k <= '9')
x = x * 10 + k - '0' ,k = getchar();
return x;
}
int main(){
cin >> n >> m;
for(int i = 1 ,u ,v ,w ; i <= m ; ++i){
u = read() ,v = read() ,w = read();
addedge(v ,u ,w);
}
bfs();
cout << dis[1] << endl;
for(int i = 1 ; i <= n ; ++i)
putchar(color[i] + '0');
return 0;
}