Codeforces Round #Pi (Div. 2) E. President and Roads(边双无向图缩点(有重边)+最短路)

E. President and Roads
time limit per test
2 seconds
memory limit per test
256 megabytes
input
standard input
output
standard output

Berland has n cities, the capital is located in city s, and the historic home town of the President is in city t (s ≠ t). The cities are connected by one-way roads, the travel time for each of the road is a positive integer.

Once a year the President visited his historic home town t, for which his motorcade passes along some path from s to t (he always returns on a personal plane). Since the president is a very busy man, he always chooses the path from s to t, along which he will travel the fastest.

The ministry of Roads and Railways wants to learn for each of the road: whether the President will definitely pass through it during his travels, and if not, whether it is possible to repair it so that it would definitely be included in the shortest path from the capital to the historic home town of the President. Obviously, the road can not be repaired so that the travel time on it was less than one. The ministry of Berland, like any other, is interested in maintaining the budget, so it wants to know the minimum cost of repairing the road. Also, it is very fond of accuracy, so it repairs the roads so that the travel time on them is always a positive integer.

Input

The first lines contain four integers nms and t (2 ≤ n ≤ 105; 1 ≤ m ≤ 105; 1 ≤ s, t ≤ n) — the number of cities and roads in Berland, the numbers of the capital and of the Presidents' home town (s ≠ t).

Next m lines contain the roads. Each road is given as a group of three integers ai, bi, li (1 ≤ ai, bi ≤ nai ≠ bi; 1 ≤ li ≤ 106) — the cities that are connected by the i-th road and the time needed to ride along it. The road is directed from city ai to city bi.

The cities are numbered from 1 to n. Each pair of cities can have multiple roads between them. It is guaranteed that there is a path froms to t along the roads.

Output

Print m lines. The i-th line should contain information about the i-th road (the roads are numbered in the order of appearance in the input).

If the president will definitely ride along it during his travels, the line must contain a single word "YES" (without the quotes).

Otherwise, if the i-th road can be repaired so that the travel time on it remains positive and then president will definitely ride along it, print space-separated word "CAN" (without the quotes), and the minimum cost of repairing.

If we can't make the road be such that president will definitely ride along it, print "NO" (without the quotes).

Sample test(s)
input
6 7 1 6
1 2 2
1 3 10
2 3 7
2 4 8
3 5 3
4 5 2
5 6 1
output
YES
CAN 2
CAN 1
CAN 1
CAN 1
CAN 1
YES
input
3 3 1 3
1 2 10
2 3 10
1 3 100
output
YES
YES
CAN 81
input
2 2 1 2
1 2 1
1 2 2
output
YES
NO
Note

The cost of repairing the road is the difference between the time needed to ride along it before and after the repairing.

In the first sample president initially may choose one of the two following ways for a ride: 1 → 2 → 4 → 5 → 6 or1 → 2 → 3 → 5 → 6.



大致题意:

有向图,有重边,国王想从s到t走最短路,对于每条路,判断:

1.这条路国王是否必走

2.若国王不是必走,是否能把长度减小一部分使国王必走,要保证路的长度始终是正数

3.否则国王必不走


思路:

先求出最短路DAG。在DAG上要是桥,则国王必走,否则,要是此边长度大于1,可以使边长减小1使国王必走

不再最短路DAG上的边根据缩短以后是否是正数而决定


有向图求桥显然不会,由于是DAG,所以直接把改成无向图然后缩点就可以辣!但是要注意有重边,所以要注意点细节


无向图缩点考虑重边模版:

int dfn[N],sta[N],top,scc,index,col[N],low[N];
void tarjan(int u,int pa)
{
        dfn[u] = low[u] = ++index;
        sta[++top] = u;
        int sz = SZ(G[u]);
        bool first = 1;
        rep(i,sz)
        {
                int v = G[u][i];
                if(first && v == pa) {  //只过滤掉那条回退边,因为要考虑重边
                        first = 0;
                        continue;
                }
                if(dfn[v] == 0)
                {
                        tarjan(v,u);
                        low[u] = min(low[u],low[v]);
                        if(low[v] > dfn[u])
                        {
                                ++scc;
                                int vv;
                                do
                                {
                                        vv = sta[top--];
                                        col[vv] = scc;
                                }while(vv != v);
                        }
                }
                else low[u] = min(low[u],dfn[v]);
        }
}
REP(u,n) if(col[u] == 0) tarjan(u,-1);       
scc++;   
while(top) col[sta[top--]] = scc; //别忘了栈剩余的


在无向图中不需要纪录low数组,因为low根本不会再次被用到,有向图的强联通分量才需要纪录low数组,所以可以有以下如此简洁的书写方式:

因为有这次的请教:

Codeforces Round #Pi (Div. 2) E. President and Roads(边双无向图缩点(有重边)+最短路)_第1张图片



//#pragma comment(linker, "/STACK:1024000000,1024000000")
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#define SZ(x) ((int)(x).size())
#define ALL(v) (v).begin(), (v).end()
#define foreach(i, v) for (__typeof((v).begin()) i = (v).begin(); i != (v).end(); ++ i)
#define reveach(i, v) for (__typeof((v).rbegin()) i = (v).rbegin(); i != (v).rend(); ++ i)
#define REP(i,n) for ( int i=1; i<=int(n); i++ )
#define rep(i,n) for ( int i=0; i pii;

template 
inline bool RD(T &ret) {
    char c; int sgn;
    if (c = getchar(), c == EOF) return 0;
    while (c != '-' && (c<'0' || c>'9')) c = getchar();
    sgn = (c == '-') ? -1 : 1;
    ret = (c == '-') ? 0 : (c - '0');
    while (c = getchar(), c >= '0'&&c <= '9') ret = ret * 10 + (c - '0');
    ret *= sgn;
    return 1;
}
template 
inline void PT(T x) {
    if (x < 0) {
        putchar('-');

        x = -x;
    }
    if (x > 9) pt(x / 10);
    putchar(x % 10 + '0');
}



const int N = 1e5+100;

struct Edge{
        int u,v,w,nxt;
        Edge(int u = 0,int v = 0,int w = 0,int nxt = 0):u(u),v(v),w(w),nxt(nxt){}
}es[N],es2[N];
int ecnt,ecnt2;
int head[N],head2[N];
int n,m,s,g;
ll diss[N],disg[N];

void dijkstra(int s,int head[],Edge es[],ll dis[]){
        priority_queue,greater > que;
        REP(i,n) dis[i] = 1LL<<50;
        que.push(pii(0,s));
        dis[s] = 0;
        while(!que.empty()){
                pii cur = que.top();
                que.pop();
                int u = cur.Y;
                if(cur.X != dis[u]) continue;
                for(int i = head[u]; ~i ; i = es[i].nxt){
                        int v = es[i].v, w = es[i].w;
                        if( dis[v] > dis[u]+w){
                                dis[v] = dis[u] + w;
                                que.push(pii(dis[v],v));
                        }
                }
        }
}

vector G[N];

int dfn[N],sta[N],top,scc,index,col[N],low[N];

void tarjan(int u,int pa)
{
        dfn[u] = low[u] = ++index;
        sta[++top] = u;
        int sz = SZ(G[u]);
        bool first = 1;
        rep(i,sz)
        {
                int v = G[u][i];
                if(first && v == pa) {  //只过滤掉那条回退边,因为要考虑重边
                        first = 0;
                        continue;
                }
                if(dfn[v] == 0)
                {
                        tarjan(v,u);
                        low[u] = min(low[u],low[v]);
                        if(low[v] > dfn[u])
                        {
                                ++scc;
                                int vv;
                                do
                                {
                                        vv = sta[top--];
                                        col[vv] = scc;
                                }while(vv != v);
                        }
                }
                else low[u] = min(low[u],dfn[v]);
        }
}


int main(){
        memset(head2,-1,sizeof(head2));
        memset(head,-1,sizeof(head));
        scanf("%d%d%d%d",&n,&m,&s,&g);
        REP(i,m){
                int u,v,w;
                RD(u),RD(v),RD(w);
                es[ecnt] = Edge(u,v,w,head[u]);
                head[u] = ecnt++;
                es2[ecnt2] = Edge(v,u,w,head2[v]);
                head2[v] = ecnt2++;
        }
        dijkstra(s,head,es,diss);
        dijkstra(g,head2,es2,disg);
        ll path = diss[g];
        REP(u,n)
                for(int i = head[u];~i; i = es[i].nxt){
                        int v = es[i].v, w = es[i].w;
                        if( diss[v]+disg[v] != path ) continue;
                        if( diss[v] == diss[u]+w) G[u].push_back(v),G[v].push_back(u);
                }
        REP(u,n) if(col[u] == 0) tarjan(u,-1);
        scc++;
        while(top) col[sta[top--]] = scc;
        rep(i,ecnt){
                int u = es[i].u, v = es[i].v, w = es[i].w;
                if( diss[v] == diss[u]+w && col[v] != col[u] && diss[v]+disg[v] == path) puts("YES");
                else if( diss[v] == diss[u]+w && col[v] == col[u] && diss[v]+disg[v] == path && w !=1 ) puts("CAN 1");
                else {
                        ll tmp = path-1-(diss[u]+disg[v]);
                        if( tmp > 0) printf("CAN %I64d\n",w-tmp);
                        else puts("NO");
                }
        }

}


你可能感兴趣的:(最短路径,连通性问题)