图给得很良心,一个s到t的有向图,权值至少为1,求出最短路,如果是一定经过的边,输出"YES",如果可以通过修改权值,保证一定经过这条边,输出"CAN",并且输出最小修改值,否则输出"NO"。保证有s到t的路径,可能有重边。
建正反两个图,分别求出s和t的最短路径,用来判断一条边是不是在最短路径上,然后把最短路径取出来建一个图求割边。
不要用spfa,最坏O(VE),(出卡spfa数据的方法:Hard Test),会TLE 109(数据好啊),自以为是的加了个优化结果跑得更慢了,估计也是那组数据卡的吧,带重边的tarjan处理:前向星i^1!=fa,或者每条边再记录一个信息,不能用v!=fa来判断。。
#include<bits/stdc++.h>
using namespace std; typedef long long ll;
#define fi first
#define se second
#define bug(x) cout<<#x<<'='<<x<<endl;
#define FOR(i,s,e) for(int i = s; i < e; i++) const int maxn = 1e5+;
const int maxe = maxn<<;
struct Graph
{
ll d[maxn];
int head[maxn],fro[maxe],to[maxe],nxt[maxe],ecnt;
ll w[maxe];
void init() { memset(head,-,sizeof(head)); ecnt = ; }
Graph(){ init(); }
void addEdge(int u,int v,ll l)
{
fro[ecnt] = u;
to[ecnt] = v;
w[ecnt] = l;
nxt[ecnt] = head[u];
head[u] = ecnt++;
}
}G1,G2,G3;
int id[maxe]; const ll INF = 0x3f3f3f3f3f3f3f3fLL; int flag[maxe]; // 0 not shortest path 1 shortest path 2 unique shortest path
int dfs_clock,dfn[maxn],low[maxn];
void Tarjan(int u,int fa)
{
dfn[u] = low[u] = ++dfs_clock;
for(int i = G3.head[u]; ~i; i = G3.nxt[i]){
if((i^) == fa) continue; // == 优先级比^高
int v = G3.to[i];
if(!dfn[v]){
Tarjan(v,i);
low[u] = min(low[u],low[v]);
if(low[v]>dfn[u]) {
flag[id[i]] = ;
}
}else { low[u] = min(low[u],low[v]); }
}
}
struct Node
{
ll d;
int u;
bool operator < (const Node& x) const{
return d > x.d;
}
}; bool vis[maxn];
void Dijkstra(int s,Graph &g)
{
priority_queue<Node> q;
memset(g.d,0x3f,sizeof(g.d));
g.d[s] = ;
q.push(Node{,s});
while(q.size()){
Node x = q.top(); q.pop();
int u = x.u;
if(vis[u]) continue;
vis[u] = true;
for(int i = g.head[u]; ~i; i = g.nxt[i] ){
int v = g.to[i];
if(g.d[v]> g.d[u]+g.w[i]){
g.d[v] = g.d[u]+g.w[i];
q.push(Node{g.d[v],v});
}
}
}
memset(vis,,sizeof(vis));
} #define local
int main()
{
#ifdef local
freopen("in.txt","r",stdin);
// freopen("out.txt","w",stdout);
#endif // local
int n,m,s,t;
scanf("%d%d%d%d",&n,&m,&s,&t);
for(int i = ; i < m; i++){
int u,v,l; scanf("%d%d%d",&u,&v,&l);
G1.addEdge(u,v,l); G2.addEdge(v,u,l);
}
Dijkstra(s,G1);
Dijkstra(t,G2);
ll shortest = G1.d[t];
for(int i = ; i < m; i++){
int u = G1.fro[i], v = G1.to[i];
if(shortest == G1.w[i] + G1.d[u] + G2.d[v] ){
id[G3.ecnt] = i; G3.addEdge(u,v,G1.w[i]);
id[G3.ecnt] = i; G3.addEdge(v,u,G1.w[i]);
flag[i] = ;
}
}
Tarjan(s,-); for(int i = ; i < m; i ++){
if(flag[i] == ) puts("YES");
else if(flag[i] == ){
if(G1.w[i]>) printf("CAN 1\n");
else puts("NO");
}else {
ll detal = G1.w[i] - shortest + G1.d[G1.fro[i]]+G2.d[G1.to[i]] + ;
if(G1.w[i] > detal)
printf("CAN %d\n",detal);
else puts("NO");
}
}
return ;
} /*
自以为是的优化:
q.push(s);
while(q.size()){
int u = q.front(); q.pop();
for(int i = G1.head[u]; ~i; i = G1.nxt[i]) if(!vis[i]) {
vis[i] = true;
int v = G1.to[i];
if(G1.d[u] + G1.w[i] == G1.d[v] && G2.d[v] + G1.w[i] == G2.d[u]){
id[G3.ecnt] = i; G3.addEdge(u,v,G1.w[i]);
id[G3.ecnt] = i; G3.addEdge(v,u,G1.w[i]);
flag[i] = 1;
q.push(v);
}
}
}
*/