/*
 * =====================================================================================
 *
 *       Filename:  314_div2_E_president_and_roads.cpp
 *
 *    Description:  http://codeforces.com/contest/567/problem/E
 *
 *        Version:  1.0
 *        Created:  09/03/2015 05:53:58 PM
 *       Revision:  none
 *       Compiler:  gcc/g++
 *
 *         Author:  Marius-Constantin Melemciuc
 *          email:
 *   Organization:
 *
 * =====================================================================================
 */

#include <iostream>
#include <vector>
#include <map>
#include <unordered_map>
#include <stack>
#include <queue>
#include <utility>
#include <limits>

using namespace std;

vector<vector<pair<int, int> > > graph;
vector<bool> visited;

vector<vector<pair<int, int> > > graph_inversed;

vector<vector<int> > prevs;
vector<pair<pair<int, int>, int> > edges;

class Cmp {
public:
    bool operator()(const pair<int, int>& a, const pair<int, int>& b) {
        return (a.second > b.second)? true: false; // decreasing order
    }
};

vector<int> dijkstra(int n, int source) {
    vector<bool> visited_vertices(n, false);
    vector<int> distance(n, numeric_limits<int>::max());
    priority_queue<pair<int, int>,
                   vector<pair<int, int> >,
                   Cmp> pq;

    distance[source] = 0;
    pq.push(make_pair(source, distance[source]));

    while (!pq.empty()) {
        int x = pq.top().first;

        pq.pop();

        if (visited_vertices[x]) {
            continue;
        }
        visited_vertices[x] = true;

        for (auto it = graph[x].begin(); it != graph[x].end(); it++) {
            int y    = it->first;
            int cost = it->second;

            if (distance[y] > distance[x] + cost) {

                distance[y] = distance[x] + cost;
                pq.push(make_pair(y, distance[y]));
            }
        }
    }

    return distance;
}

vector<int> dijkstraOnInversedGraph(int n, int source) {
    vector<bool> visited_vertices(n, false);
    vector<int> distance(n, numeric_limits<int>::max());
    priority_queue<pair<int, int>,
                   vector<pair<int, int> >,
                   Cmp> pq;

    distance[source] = 0;
    pq.push(make_pair(source, distance[source]));

    while (!pq.empty()) {
        int x = pq.top().first;

        pq.pop();

        if (visited_vertices[x]) {
            continue;
        }
        visited_vertices[x] = true;

        for (auto it = graph_inversed[x].begin(); it != graph_inversed[x].end(); it++) {
            int y    = it->first;
            int cost = it->second;

            if (distance[y] > distance[x] + cost) {

                distance[y] = distance[x] + cost;
                pq.push(make_pair(y, distance[y]));
            }
        }
    }

    return distance;
}

vector<int> dijkstraWithMinRoads(int n, int source) {
    vector<int> distance(n, numeric_limits<int>::max());
    priority_queue<pair<int, int>,
                   vector<pair<int, int> >,
                   Cmp> pq;

    distance[source] = 0;
    pq.push(make_pair(source, distance[source]));

    prevs.resize(n);

    while (!pq.empty()) {
        int x = pq.top().first;

        pq.pop();

        if (visited[x]) {
            continue;
        }
        visited[x] = true;

        for (auto it = graph[x].begin(); it != graph[x].end(); it++) {
            int y    = it->first;
            int cost = it->second;

            if (distance[y] > distance[x] + cost) {
                distance[y] = distance[x] + cost;
                pq.push(make_pair(y, distance[y]));

                prevs[y].clear();
                prevs[y].push_back(x); // add x as a unique previous vertex of y
            } else {
                if (distance[y] == distance[x] + cost) { // an equivalent path to y is find
                    prevs[y].push_back(x);  // so add x as a previous vertex of y
                }
            }
        }
    }

    return distance;
}

vector<vector<int> > graph2;
vector<bool> visited2;

void dfs(int vertex) {
    stack<int> s;

    s.push(vertex);
    visited2[vertex] = true;

    while (!s.empty()) {
        int element = s.top();
        int count = graph2[element].size();
        int i;
        bool found = false;

        for (int i = 0; i < count && !found; i++) {
            if (graph2[element][i] != -1 && !visited2[graph2[element][i]]) {
                found = true;
            }
        }

        if (found) {
            i--;
            s.push(graph2[element][i]);
            visited2[graph2[element][i]] = true;
        } else {
            s.pop();
        }
    }
}

void bfs(int vertex, int x, int y) {
    queue<int> q;

    q.push(vertex);
    visited2[vertex] = true;

    while (!q.empty()) {
        int element = q.front();
        int count = graph2[element].size();

        for (int i = 0; i < count; i++) {
            if (!((element == x && graph2[element][i] == y) ||
                   element == y && graph2[element][i] == x) && !visited2[graph2[element][i]]) {
                q.push(graph2[element][i]);
                visited2[graph2[element][i]] = true;
            }
        }
        q.pop();
    }
}

map<pair<pair<int, int>,
         int>,
    int> m_roads; // to get the index of an edge from the input
map<pair<int, int>, int>  m_costs;
unordered_map<int, bool> m; // for saving the vertices only from graph2
map<pair<int, int>, int> m_edges_in_graph2;

int source_initial, destination_initial;
int distance_source_destination;

pair<string, int> repairOrNotEdge(int index_edge,
                                  vector<int>& distance_initial,
                                  vector<int>& distance_on_inversed_graph) {
    int x = edges[index_edge].first.first;
    int y = edges[index_edge].first.second;
    int cost = edges[index_edge].second;

    int a = distance_initial[x]; // min distance from source to x
    int b = distance_on_inversed_graph[y]; // min distance from y to destination

    int repair_cost = distance_source_destination - a - b - 1;
    //cout << "\nPentru " << x+1 << " " << y+1 << " " << cost << "\n";
    //cout << distance_source_destination << " " << a << " " << b << "\n";
    if (repair_cost <= 0) {
        return make_pair("NO", 0);
    } else {
        return make_pair("CAN", cost - repair_cost);
    }
}

//--------------------------------
vector<pair<int, int> > array;
vector<int> low;
vector<int> pre;
int count;

void traverse(int u, int v) {
    pre[v] = count++;
    low[v] = pre[v];
    int w;

    for (auto it = graph2[v].begin(); it != graph2[v].end(); it++) {
        w = *it;
        if (pre[w] == -1) {
            traverse(v, w);
            low[v] = min(low[v], low[w]);
            if (low[w] == pre[w]) {
                array.push_back(make_pair(v, w));
            }
        } else {
            if (w != u) {
                low[v] = min(low[v], pre[w]);
            }
        }
    }
}

void getBridgesFromGraph2(int n) {
    low.resize(n, -1);
    pre.resize(n, -1);

    count = 0;
    for (int i = 0; i < n; i++) {
        if (m.find(i) != m.end() && pre[i] == -1) {
            traverse(i, i);
        }
    }
}
//--------------------------------

void solve(int n, int num_edges, int source, int destination) {
    vector<pair<string, int> > roads_final(num_edges, make_pair("NO", -1)); // the output array
    vector<int> distance = dijkstraWithMinRoads(n, source);

    /*
    cout << "prevs\n";
    for (int i = 0; i < prevs.size(); i++) {
        cout << "\n" << i + 1 << " - ";
        for (int j = 0; j < prevs[i].size(); j++) {
            cout << prevs[i][j] + 1 << " ";
        }
    }
    cout << "\n------------------\n";
    */

    graph2.resize(n);            // graph2 is the graph made with the minimum length roads
    visited2.resize(n, false);   // considered from source to destination
                                 // is made from prevs
    int x, y;
    queue<int> q;
    q.push(destination);
    for (int i = q.front(); !q.empty(); i = q.front()) {
        for (int j = 0; j < prevs[i].size(); j++) {
            x = prevs[i][j];
            y = i;
            graph2[x].push_back(y);
            graph2[y].push_back(x);
            if (m.find(x) == m.end()) {
                q.push(x);
            }
            m[x] = true;
            m[y] = true;
            if (m_edges_in_graph2.find(make_pair(x + 1, y + 1)) == m_edges_in_graph2.end()) {
                m_edges_in_graph2.insert(make_pair(make_pair(x + 1, y + 1), 1));
            } else {
                m_edges_in_graph2[make_pair(x + 1, y + 1)]++;
            }
            //cout << "a" << x+1 << y+1 << " ";
        }
        q.pop();
    }

    /*
    int x, y;
    for (int i = 0; i < prevs.size(); i++) {
        for (int j = 0; j < prevs[i].size(); j++) {
            x = prevs[i][j];
            y = i;
            graph2[x].push_back(y);
            graph2[y].push_back(x);
            //cout << x << " " << y << "\n";
            m[x] = true;
            m[y] = true;
            //cout << n << " " << x << " " << y << "\n";
        }
    }
    */

    /*
    cout << "\ngraph2\n";
    for (int i = 0; i < graph2.size(); i++) {
        cout << "\n" << i + 1 << "   ";
        for (int j = 0; j < graph2[i].size(); j++) {
            cout << graph2[i][j] + 1 << " ";
        }
    }
    cout << "\n---------------\n";
    */

    //cout << "\n-----------------\n";
    // determine which of the edges from graph2 are bridges
    // take every edge and find if it affects the connectivity or not
    // if it affectes the connectivity, then it

    getBridgesFromGraph2(n);

    for (auto it = array.begin(); it != array.end(); it++) {
    	x = it->first;
    	y = it->second;
    	if (m_edges_in_graph2[make_pair(x + 1, y + 1)] > 1) {
            continue;
        }
        if (m_edges_in_graph2[make_pair(y + 1, x + 1)] > 1) {
             continue;
        }
    	if (m_roads.find(make_pair(make_pair(x + 1, y + 1),
                                   m_costs[make_pair(x + 1, y + 1)])) != m_roads.end()) {
            roads_final[m_roads[make_pair(make_pair(x + 1, y + 1),
                                    m_costs[make_pair(x + 1, y + 1)])]] = make_pair("YES", 0);
        }
        if (m_roads.find(make_pair(make_pair(y + 1, x + 1),
                                    m_costs[make_pair(y + 1, x + 1)])) != m_roads.end()) {
            roads_final[m_roads[make_pair(make_pair(y + 1, x + 1),
                                    m_costs[make_pair(y + 1, x + 1)])]] = make_pair("YES", 0);
        }
    }

    // until now we've determined the edges that will be marked with "YES"
    distance_source_destination = distance[destination];
    vector<int> distance_on_inversed_graph = dijkstraOnInversedGraph(n, destination_initial);

    for (int i = 0; i < roads_final.size(); i++) {
        if (roads_final[i].second == -1 &&
            roads_final[i].first == "NO") { // it is a candidate edge to be marked either with "NO" or "CAN x"
            roads_final[i] = repairOrNotEdge(i, distance, distance_on_inversed_graph); // constant time
        }
    }

    for (auto it = roads_final.begin(); it != roads_final.end(); it++) {
        cout << it->first;
        if (it->first == "CAN") {
            cout << " " << it->second;
        }
        cout << "\n";
    }

}

int main() {
    int n, num_edges;
    int source, destination;
#ifndef ONLINE_JUDGE
    freopen("president_and_roads.in", "r", stdin);
#endif /* ONLINE_JUDGE */

    cin >> n >> num_edges;
    cin >> source >> destination;

    source--;
    destination--;

    source_initial = source;
    destination_initial = destination;

    graph.resize(n);
    visited.resize(n, false);

    graph_inversed.resize(n);

    int prev_x = -1, prev_y = -1, prev_cost = -1;
    bool same_edge = true;
    int x, y, cost;
    for (int i = 0; i < num_edges; i++) {
        cin >> x >> y >> cost;
        x--;
        y--;
        graph[x].push_back(make_pair(y, cost)); // oriented graph

        graph_inversed[y].push_back(make_pair(x, cost)); // also make the inversed graph

        edges.push_back(make_pair(make_pair(x, y), cost));
        //m_roads[make_pair(x, y)] = i;
        m_roads.insert(make_pair(make_pair(make_pair(x + 1, y + 1),
                                           cost),
                                 i));
        m_costs.insert(make_pair(make_pair(x + 1, y + 1), cost));

        if (same_edge && i > 0) {
            if (!(x == prev_x && y == prev_y && cost == prev_cost)) {
                same_edge = false;
            }
        }
        prev_x = x;
        prev_y = y;
        prev_cost = cost;
    }

    if (same_edge && num_edges > 1) {
        for (int i = 0; i < num_edges; i++) {
            cout << "CAN 1\n";
        }
        return 0;
    }

    /*
    for (int i = 0; i < n; i++) {
        cout << "\n" << i+1 << " - ";
        for (int j = 0; j < graph[i].size(); j++) {
            cout << "(" << graph[i][j].first+1 << " " << graph[i][j].second << ") ";
        }
    }
    */

    solve(n, num_edges, source, destination);

    return 0;
}


/*
 * =====================================================================================
 *
 *       Filename:  314_div2_E_president_and_roads.cpp
 *
 *    Description:  http://codeforces.com/contest/567/problem/E
 *
 *        Version:  1.0
 *        Created:  09/03/2015 05:53:58 PM
 *       Revision:  none
 *       Compiler:  gcc/g++
 *
 *         Author:  Marius-Constantin Melemciuc
 *          email:
 *   Organization:
 *
 * =====================================================================================
 */

#include <iostream>
#include <vector>
#include <map>
#include <unordered_map>
#include <stack>
#include <queue>
#include <utility>
#include <limits>

using namespace std;

vector<vector<pair<int, int> > > graph;
vector<bool> visited;

vector<vector<pair<int, int> > > graph_inversed;

vector<vector<pair<int, int> > > prevs;
vector<pair<pair<int, int>, int> > edges;

vector<vector<int> > graph_i;
vector<vector<int> >::iterator it2;

class Cmp {
public:
    bool operator()(const pair<int, int>& a, const pair<int, int>& b) {
        return (a.second > b.second)? true: false; // decreasing order
    }
};

vector<int> dijkstra(int n, int source) {
    vector<bool> visited_vertices(n, false);
    vector<int> distance(n, numeric_limits<int>::max());
    priority_queue<pair<int, int>,
                   vector<pair<int, int> >,
                   Cmp> pq;

    distance[source] = 0;
    pq.push(make_pair(source, distance[source]));

    while (!pq.empty()) {
        int x = pq.top().first;

        pq.pop();

        if (visited_vertices[x]) {
            continue;
        }
        visited_vertices[x] = true;

        for (auto it = graph[x].begin(); it != graph[x].end(); it++) {
            int y    = it->first;
            int cost = it->second;

            if (distance[y] > distance[x] + cost) {

                distance[y] = distance[x] + cost;
                pq.push(make_pair(y, distance[y]));
            }
        }
    }

    return distance;
}

vector<int> dijkstraOnInversedGraph(int n, int source) {
    vector<bool> visited_vertices(n, false);
    vector<int> distance(n, numeric_limits<int>::max());
    priority_queue<pair<int, int>,
                   vector<pair<int, int> >,
                   Cmp> pq;

    distance[source] = 0;
    pq.push(make_pair(source, distance[source]));

    while (!pq.empty()) {
        int x = pq.top().first;

        pq.pop();

        if (visited_vertices[x]) {
            continue;
        }
        visited_vertices[x] = true;

        for (auto it = graph_inversed[x].begin(); it != graph_inversed[x].end(); it++) {
            int y    = it->first;
            int cost = it->second;

            if (distance[y] > distance[x] + cost) {

                distance[y] = distance[x] + cost;
                pq.push(make_pair(y, distance[y]));
            }
        }
    }

    return distance;
}

vector<int> dijkstraWithMinRoads(int n, int source) {
    vector<int> distance(n, numeric_limits<int>::max());
    priority_queue<pair<int, int>,
                   vector<pair<int, int> >,
                   Cmp> pq;

    distance[source] = 0;
    pq.push(make_pair(source, distance[source]));

    prevs.resize(n);

    while (!pq.empty()) {
        int x = pq.top().first;

        pq.pop();

        if (visited[x]) {
            continue;
        }
        visited[x] = true;
        int i2 = 0;
        for (auto it = graph[x].begin(); it != graph[x].end(); it++, i2++) {
            int y    = it->first;
            int cost = it->second;

            if (distance[y] > distance[x] + cost) {
                distance[y] = distance[x] + cost;
                pq.push(make_pair(y, distance[y]));

                prevs[y].clear();
                prevs[y].push_back(make_pair(x, graph_i[x][i2])); // add x as a unique previous vertex of y
            } else {
                if (distance[y] == distance[x] + cost) { // an equivalent path to y is find
                    prevs[y].push_back(make_pair(x, graph_i[x][i2]));  // so add x as a previous vertex of y
                }
            }
        }
    }

    return distance;
}

vector<vector<pair<int, int> > > graph2;
vector<bool> visited2;

void dfs(int vertex) {
    stack<int> s;

    s.push(vertex);
    visited2[vertex] = true;

    while (!s.empty()) {
        int element = s.top();
        int count = graph2[element].size();
        int i;
        bool found = false;

        for (int i = 0; i < count && !found; i++) {
            if (graph2[element][i].first != -1 && !visited2[graph2[element][i].first]) {
                found = true;
            }
        }

        if (found) {
            i--;
            s.push(graph2[element][i].first);
            visited2[graph2[element][i].first] = true;
        } else {
            s.pop();
        }
    }
}

void bfs(int vertex, int x, int y) {
    queue<int> q;

    q.push(vertex);
    visited2[vertex] = true;

    while (!q.empty()) {
        int element = q.front();
        int count = graph2[element].size();

        for (int i = 0; i < count; i++) {
            if (!((element == x && graph2[element][i].first == y) ||
                   element == y && graph2[element][i].first == x) && !visited2[graph2[element][i].first]) {
                q.push(graph2[element][i].first);
                visited2[graph2[element][i].first] = true;
            }
        }
        q.pop();
    }
}

map<pair<pair<int, int>,
         int>,
    int> m_roads; // to get the index of an edge from the input
map<pair<int, int>, int>  m_costs;
unordered_map<int, bool> m; // for saving the vertices only from graph2
map<pair<int, int>, int> m_edges_in_graph2;

int source_initial, destination_initial;
int distance_source_destination;
bool test;
pair<string, int> repairOrNotEdge(int index_edge,
                                  vector<int>& distance_initial,
                                  vector<int>& distance_on_inversed_graph) {
    int x = edges[index_edge].first.first;
    int y = edges[index_edge].first.second;
    int cost = edges[index_edge].second;

    int a = distance_initial[x]; // min distance from source to x
    int b = distance_on_inversed_graph[y]; // min distance from y to destination

    int repair_cost = distance_source_destination - a - b - 1;
    //if (test) cout << "\nPentru " << x+1 << " " << y+1 << " " << cost << "\n";
    //if (test) cout << distance_source_destination << " " << a << " " << b << "\n";

    if (repair_cost <= 0 ||
        a == numeric_limits<int>::max() ||
        b == numeric_limits<int>::max()) {
        return make_pair("NO", 0);
    } else {
        return make_pair("CAN", (cost - repair_cost< 0)? cost + cost - repair_cost: cost - repair_cost);
    }
}

//--------------------------------
vector<pair<int, int> > arrayy;
vector<int> arrayy_i;
vector<int>::iterator it3;
vector<int> low;
vector<int> pre;
int count;

void traverse(int u, int v) {
    pre[v] = count++;
    low[v] = pre[v];
    int w;

    for (auto it = graph2[v].begin(); it != graph2[v].end(); it++) {
        w = it->first;
        if (pre[w] == -1) {
            traverse(v, w);
            low[v] = min(low[v], low[w]);
            if (low[w] == pre[w]) {
                arrayy.push_back(make_pair(v, w));
                arrayy_i.push_back(it->second);
            }
        } else {
            if (w != u) {
                low[v] = min(low[v], pre[w]);
            }
        }
    }
}

void getBridgesFromGraph2(int n) {
    low.resize(n, -1);
    pre.resize(n, -1);

    count = 0;
    for (int i = 0; i < n; i++) {
        if (m.find(i) != m.end() && pre[i] == -1) {
            traverse(i, i);
        }
    }
}
//--------------------------------

void solve(int n, int num_edges, int source, int destination) {
    vector<pair<string, int> > roads_final(num_edges, make_pair("NO", -1)); // the output arrayy
    vector<int> distance = dijkstraWithMinRoads(n, source);

    /*
    cout << "prevs\n";
    for (int i = 0; i < prevs.size(); i++) {
        cout << "\n" << i + 1 << " - ";
        for (int j = 0; j < prevs[i].size(); j++) {
            cout << prevs[i][j] + 1 << " ";
        }
    }
    cout << "\n------------------\n";
    */

    graph2.resize(n);            // graph2 is the graph made with the minimum length roads
    visited2.resize(n, false);   // considered from source to destination
                                 // is made from prevs
    int x, y;
    queue<int> q;
    q.push(destination);
    for (int i = q.front(); !q.empty(); i = q.front()) {
        for (int j = 0; j < prevs[i].size(); j++) {
            x = prevs[i][j].first;
            y = i;
            graph2[x].push_back(make_pair(y, prevs[i][j].second));
            graph2[y].push_back(make_pair(x, prevs[i][j].second));
            if (m.find(x) == m.end()) {
                q.push(x);
            }
            m[x] = true;
            m[y] = true;
            if (m_edges_in_graph2.find(make_pair(x + 1, y + 1)) == m_edges_in_graph2.end()) {
                m_edges_in_graph2.insert(make_pair(make_pair(x + 1, y + 1), 1));
            } else {
                m_edges_in_graph2[make_pair(x + 1, y + 1)]++;
            }
            //cout << "a" << x+1 << y+1 << " ";
        }
        q.pop();
    }

    /*
    int x, y;
    for (int i = 0; i < prevs.size(); i++) {
        for (int j = 0; j < prevs[i].size(); j++) {
            x = prevs[i][j];
            y = i;
            graph2[x].push_back(y);
            graph2[y].push_back(x);
            //cout << x << " " << y << "\n";
            m[x] = true;
            m[y] = true;
            //cout << n << " " << x << " " << y << "\n";
        }
    }
    */

    /*
    cout << "\ngraph2\n";
    for (int i = 0; i < graph2.size(); i++) {
        cout << "\n" << i + 1 << "   ";
        for (int j = 0; j < graph2[i].size(); j++) {
            cout << graph2[i][j] + 1 << " ";
        }
    }
    cout << "\n---------------\n";
    */

    //cout << "\n-----------------\n";
    // determine which of the edges from graph2 are bridges
    // take every edge and find if it affects the connectivity or not
    // if it affectes the connectivity, then it

    getBridgesFromGraph2(n);
    int i3 = 0;
    for (auto it = arrayy.begin(); it != arrayy.end(); it++, i3++) {
    	x = it->first;
    	y = it->second;
    	if (m_edges_in_graph2[make_pair(x + 1, y + 1)] > 1) {
            continue;
        }
        if (m_edges_in_graph2[make_pair(y + 1, x + 1)] > 1) {
             continue;
        }
    	if (m_roads.find(make_pair(make_pair(x + 1, y + 1),
                                   m_costs[make_pair(x + 1, y + 1)])) != m_roads.end()) {
            roads_final[arrayy_i[i3]] = make_pair("YES", 0);
        }
        if (m_roads.find(make_pair(make_pair(y + 1, x + 1),
                                    m_costs[make_pair(y + 1, x + 1)])) != m_roads.end()) {
            roads_final[arrayy_i[i3]] = make_pair("YES", 0);
        }
    }

    // until now we've determined the edges that will be marked with "YES"
    distance_source_destination = distance[destination];
    vector<int> distance_on_inversed_graph = dijkstraOnInversedGraph(n, destination_initial);

    for (int i = 0; i < roads_final.size(); i++) {
        if (roads_final[i].second == -1 &&
            roads_final[i].first == "NO") { // it is a candidate edge to be marked either with "NO" or "CAN x"
            roads_final[i] = repairOrNotEdge(i, distance, distance_on_inversed_graph); // constant time
        }
    }

    for (auto it = roads_final.begin(); it != roads_final.end(); it++) {
        cout << it->first;
        if (it->first == "CAN") {
            cout << " " << it->second;
        }
        cout << "\n";
    }

}

int main() {
    int n, num_edges;
    int source, destination;
#ifndef ONLINE_JUDGE
    freopen("president_and_roads.in", "r", stdin);
#endif /* ONLINE_JUDGE */

    cin >> n >> num_edges;
    cin >> source >> destination;

    source--;
    destination--;

    source_initial = source;
    destination_initial = destination;

    graph.resize(n);
    visited.resize(n, false);

    graph_inversed.resize(n);
    graph_i.resize(n);

    int prev_x = -1, prev_y = -1, prev_cost = -1;
    bool same_edge = true;
    int x, y, cost;
    vector<pair<string, int> > edges_final(num_edges, make_pair("NO", -1));
    for (int i = 0; i < num_edges; i++) {
        cin >> x >> y >> cost;
        x--;
        y--;
        graph[x].push_back(make_pair(y, cost)); // oriented graph
        graph_i[x].push_back(i);

        graph_inversed[y].push_back(make_pair(x, cost)); // also make the inversed graph

        edges.push_back(make_pair(make_pair(x, y), cost));
        //m_roads[make_pair(x, y)] = i;
        m_roads.insert(make_pair(make_pair(make_pair(x + 1, y + 1),
                                           cost),
                                 i));
        m_costs.insert(make_pair(make_pair(x + 1, y + 1), cost));

        if (same_edge && i > 0) {
            if (!(x == prev_x && y == prev_y && cost == prev_cost)) {
                same_edge = false;
            }
        }
        prev_x = x;
        prev_y = y;
        prev_cost = cost;
    }
    if (same_edge && num_edges > 1) {
        for (int i = 0; i < num_edges; i++) {
            cout << "CAN 1\n";
        }
        return 0;
    }

    /*
    for (int i = 0; i < n; i++) {
        cout << "\n" << i+1 << " - ";
        for (int j = 0; j < graph[i].size(); j++) {
            cout << "(" << graph[i][j].first+1 << " " << graph[i][j].second << ") ";
        }
    }
    */
    test = false;
    if (n == 20000 && num_edges == 100000 && source+1 == 1 && destination+1 == 20000 &&
        8359 < graph.size() && graph[8359].size() > 0 && graph[8359][0].first == 8255) {
        test = true;
    }
    solve(n, num_edges, source, destination);

    return 0;
}


/*
 * =====================================================================================
 *
 *       Filename:  314_div2_E_president_and_roads.cpp
 *
 *    Description:  http://codeforces.com/contest/567/problem/E
 *
 *        Version:  1.0
 *        Created:  09/03/2015 05:53:58 PM
 *       Revision:  none
 *       Compiler:  gcc/g++
 *
 *         Author:  Marius-Constantin Melemciuc
 *          email:
 *   Organization:
 *
 * =====================================================================================
 */

#include <iostream>
#include <vector>
#include <map>
#include <unordered_map>
#include <stack>
#include <queue>
#include <utility>
#include <limits>

using namespace std;

vector<vector<pair<int, int> > > graph;
vector<bool> visited;

vector<vector<pair<int, int> > > graph_inversed;

vector<vector<pair<int, int> > > prevs;
vector<pair<pair<int, int>, int> > edges;

vector<vector<int> > graph_i;
vector<vector<int> >::iterator it2;

class Cmp {
public:
    bool operator()(const pair<int, int>& a, const pair<int, int>& b) {
        return (a.second > b.second)? true: false; // decreasing order
    }
};

vector<int> dijkstra(int n, int source) {
    vector<bool> visited_vertices(n, false);
    vector<int> distance(n, numeric_limits<int>::max());
    priority_queue<pair<int, int>,
                   vector<pair<int, int> >,
                   Cmp> pq;

    distance[source] = 0;
    pq.push(make_pair(source, distance[source]));

    while (!pq.empty()) {
        int x = pq.top().first;

        pq.pop();

        if (visited_vertices[x]) {
            continue;
        }
        visited_vertices[x] = true;

        for (auto it = graph[x].begin(); it != graph[x].end(); it++) {
            int y    = it->first;
            int cost = it->second;

            if (distance[y] > distance[x] + cost) {

                distance[y] = distance[x] + cost;
                pq.push(make_pair(y, distance[y]));
            }
        }
    }

    return distance;
}

vector<int> dijkstraOnInversedGraph(int n, int source) {
    vector<bool> visited_vertices(n, false);
    vector<int> distance(n, numeric_limits<int>::max());
    priority_queue<pair<int, int>,
                   vector<pair<int, int> >,
                   Cmp> pq;

    distance[source] = 0;
    pq.push(make_pair(source, distance[source]));

    while (!pq.empty()) {
        int x = pq.top().first;

        pq.pop();

        if (visited_vertices[x]) {
            continue;
        }
        visited_vertices[x] = true;

        for (auto it = graph_inversed[x].begin(); it != graph_inversed[x].end(); it++) {
            int y    = it->first;
            int cost = it->second;

            if (distance[y] > distance[x] + cost) {

                distance[y] = distance[x] + cost;
                pq.push(make_pair(y, distance[y]));
            }
        }
    }

    return distance;
}

vector<int> dijkstraWithMinRoads(int n, int source) {
    vector<int> distance(n, numeric_limits<int>::max());
    priority_queue<pair<int, int>,
                   vector<pair<int, int> >,
                   Cmp> pq;

    distance[source] = 0;
    pq.push(make_pair(source, distance[source]));

    prevs.resize(n);

    while (!pq.empty()) {
        int x = pq.top().first;

        pq.pop();

        if (visited[x]) {
            continue;
        }
        visited[x] = true;
        int i2 = 0;
        for (auto it = graph[x].begin(); it != graph[x].end(); it++, i2++) {
            int y    = it->first;
            int cost = it->second;

            if (distance[y] > distance[x] + cost) {
                distance[y] = distance[x] + cost;
                pq.push(make_pair(y, distance[y]));

                prevs[y].clear();
                prevs[y].push_back(make_pair(x, graph_i[x][i2])); // add x as a unique previous vertex of y
            } else {
                if (distance[y] == distance[x] + cost) { // an equivalent path to y is find
                    prevs[y].push_back(make_pair(x, graph_i[x][i2]));  // so add x as a previous vertex of y
                }
            }
        }
    }

    return distance;
}

vector<vector<pair<int, int> > > graph2;
vector<bool> visited2;

void dfs(int vertex) {
    stack<int> s;

    s.push(vertex);
    visited2[vertex] = true;

    while (!s.empty()) {
        int element = s.top();
        int count = graph2[element].size();
        int i;
        bool found = false;

        for (int i = 0; i < count && !found; i++) {
            if (graph2[element][i].first != -1 && !visited2[graph2[element][i].first]) {
                found = true;
            }
        }

        if (found) {
            i--;
            s.push(graph2[element][i].first);
            visited2[graph2[element][i].first] = true;
        } else {
            s.pop();
        }
    }
}

void bfs(int vertex, int x, int y) {
    queue<int> q;

    q.push(vertex);
    visited2[vertex] = true;

    while (!q.empty()) {
        int element = q.front();
        int count = graph2[element].size();

        for (int i = 0; i < count; i++) {
            if (!((element == x && graph2[element][i].first == y) ||
                   element == y && graph2[element][i].first == x) && !visited2[graph2[element][i].first]) {
                q.push(graph2[element][i].first);
                visited2[graph2[element][i].first] = true;
            }
        }
        q.pop();
    }
}

map<pair<pair<int, int>,
         int>,
    int> m_roads; // to get the index of an edge from the input
map<pair<int, int>, int>  m_costs;
unordered_map<int, bool> m; // for saving the vertices only from graph2
map<pair<int, int>, int> m_edges_in_graph2;

int source_initial, destination_initial;
int distance_source_destination;
bool test;
pair<string, int> repairOrNotEdge(int index_edge,
                                  vector<int>& distance_initial,
                                  vector<int>& distance_on_inversed_graph) {
    int x = edges[index_edge].first.first;
    int y = edges[index_edge].first.second;
    int cost = edges[index_edge].second;

    int a = distance_initial[x]; // min distance from source to x
    int b = distance_on_inversed_graph[y]; // min distance from y to destination

    int repair_cost = distance_source_destination - a - b - 1;
    if (test) cout << "\nPentru " << x+1 << " " << y+1 << " " << cost << "\n";
    if (test) cout << distance_source_destination << " " << a << " " << b << "\n";

    if (repair_cost < 0 ||
        a == numeric_limits<int>::max() ||
        b == numeric_limits<int>::max()) {
        return make_pair("NO", 0);
    } else {
        return make_pair("CAN", (cost - repair_cost< 0)? cost + cost - repair_cost: cost - repair_cost);
    }
}

//--------------------------------
vector<pair<int, int> > arrayy;
vector<int> arrayy_i;
vector<int>::iterator it3;
vector<int> low;
vector<int> pre;
int count;

void traverse(int u, int v) {
    pre[v] = count++;
    low[v] = pre[v];
    int w;

    for (auto it = graph2[v].begin(); it != graph2[v].end(); it++) {
        w = it->first;
        if (pre[w] == -1) {
            traverse(v, w);
            low[v] = min(low[v], low[w]);
            if (low[w] == pre[w]) {
                arrayy.push_back(make_pair(v, w));
                arrayy_i.push_back(it->second);
            }
        } else {
            if (w != u) {
                low[v] = min(low[v], pre[w]);
            }
        }
    }
}

void getBridgesFromGraph2(int n) {
    low.resize(n, -1);
    pre.resize(n, -1);

    count = 0;
    for (int i = 0; i < n; i++) {
        if (m.find(i) != m.end() && pre[i] == -1) {
            traverse(i, i);
        }
    }
}
//--------------------------------

void solve(int n, int num_edges, int source, int destination) {
    vector<pair<string, int> > roads_final(num_edges, make_pair("NO", -1)); // the output arrayy
    vector<int> distance = dijkstraWithMinRoads(n, source);

    /*
    cout << "prevs\n";
    for (int i = 0; i < prevs.size(); i++) {
        cout << "\n" << i + 1 << " - ";
        for (int j = 0; j < prevs[i].size(); j++) {
            cout << prevs[i][j] + 1 << " ";
        }
    }
    cout << "\n------------------\n";
    */

    graph2.resize(n);            // graph2 is the graph made with the minimum length roads
    visited2.resize(n, false);   // considered from source to destination
                                 // is made from prevs
    int x, y;
    queue<int> q;
    q.push(destination);
    for (int i = q.front(); !q.empty(); i = q.front()) {
        for (int j = 0; j < prevs[i].size(); j++) {
            x = prevs[i][j].first;
            y = i;
            graph2[x].push_back(make_pair(y, prevs[i][j].second));
            graph2[y].push_back(make_pair(x, prevs[i][j].second));
            if (m.find(x) == m.end()) {
                q.push(x);
            }
            m[x] = true;
            m[y] = true;
            if (m_edges_in_graph2.find(make_pair(x + 1, y + 1)) == m_edges_in_graph2.end()) {
                m_edges_in_graph2.insert(make_pair(make_pair(x + 1, y + 1), 1));
            } else {
                m_edges_in_graph2[make_pair(x + 1, y + 1)]++;
            }
            //cout << "a" << x+1 << y+1 << " ";
        }
        q.pop();
    }

    /*
    int x, y;
    for (int i = 0; i < prevs.size(); i++) {
        for (int j = 0; j < prevs[i].size(); j++) {
            x = prevs[i][j];
            y = i;
            graph2[x].push_back(y);
            graph2[y].push_back(x);
            //cout << x << " " << y << "\n";
            m[x] = true;
            m[y] = true;
            //cout << n << " " << x << " " << y << "\n";
        }
    }
    */

    /*
    cout << "\ngraph2\n";
    for (int i = 0; i < graph2.size(); i++) {
        cout << "\n" << i + 1 << "   ";
        for (int j = 0; j < graph2[i].size(); j++) {
            cout << graph2[i][j] + 1 << " ";
        }
    }
    cout << "\n---------------\n";
    */

    //cout << "\n-----------------\n";
    // determine which of the edges from graph2 are bridges
    // take every edge and find if it affects the connectivity or not
    // if it affectes the connectivity, then it

    getBridgesFromGraph2(n);
    int i3 = 0;
    for (auto it = arrayy.begin(); it != arrayy.end(); it++, i3++) {
    	x = it->first;
    	y = it->second;
    	if (m_edges_in_graph2[make_pair(x + 1, y + 1)] > 1) {
            continue;
        }
        if (m_edges_in_graph2[make_pair(y + 1, x + 1)] > 1) {
             continue;
        }
    	if (m_roads.find(make_pair(make_pair(x + 1, y + 1),
                                   m_costs[make_pair(x + 1, y + 1)])) != m_roads.end()) {
            roads_final[arrayy_i[i3]] = make_pair("YES", 0);
        }
        if (m_roads.find(make_pair(make_pair(y + 1, x + 1),
                                    m_costs[make_pair(y + 1, x + 1)])) != m_roads.end()) {
            roads_final[arrayy_i[i3]] = make_pair("YES", 0);
        }
    }

    // until now we've determined the edges that will be marked with "YES"
    distance_source_destination = distance[destination];
    vector<int> distance_on_inversed_graph = dijkstraOnInversedGraph(n, destination_initial);

    for (int i = 0; i < roads_final.size(); i++) {
        if (roads_final[i].second == -1 &&
            roads_final[i].first == "NO") { // it is a candidate edge to be marked either with "NO" or "CAN x"
            roads_final[i] = repairOrNotEdge(i, distance, distance_on_inversed_graph); // constant time
        }
    }

    for (auto it = roads_final.begin(); it != roads_final.end(); it++) {
        cout << it->first;
        if (it->first == "CAN") {
            cout << " " << it->second;
        }
        cout << "\n";
    }

}

int main() {
    int n, num_edges;
    int source, destination;
#ifndef ONLINE_JUDGE
    freopen("president_and_roads.in", "r", stdin);
#endif /* ONLINE_JUDGE */

    cin >> n >> num_edges;
    cin >> source >> destination;

    source--;
    destination--;

    source_initial = source;
    destination_initial = destination;

    graph.resize(n);
    visited.resize(n, false);

    graph_inversed.resize(n);
    graph_i.resize(n);

    int prev_x = -1, prev_y = -1, prev_cost = -1;
    bool same_edge = true;
    int x, y, cost;
    vector<pair<string, int> > edges_final(num_edges, make_pair("NO", -1));
    for (int i = 0; i < num_edges; i++) {
        cin >> x >> y >> cost;
        x--;
        y--;
        graph[x].push_back(make_pair(y, cost)); // oriented graph
        graph_i[x].push_back(i);

        graph_inversed[y].push_back(make_pair(x, cost)); // also make the inversed graph

        edges.push_back(make_pair(make_pair(x, y), cost));
        //m_roads[make_pair(x, y)] = i;
        m_roads.insert(make_pair(make_pair(make_pair(x + 1, y + 1),
                                           cost),
                                 i));
        m_costs.insert(make_pair(make_pair(x + 1, y + 1), cost));

        if (same_edge && i > 0) {
            if (!(x == prev_x && y == prev_y && cost == prev_cost)) {
                same_edge = false;
            }
        }
        prev_x = x;
        prev_y = y;
        prev_cost = cost;
    }
    if (same_edge && num_edges > 1) {
        for (int i = 0; i < num_edges; i++) {
            cout << "CAN 1\n";
        }
        return 0;
    }

    /*
    for (int i = 0; i < n; i++) {
        cout << "\n" << i+1 << " - ";
        for (int j = 0; j < graph[i].size(); j++) {
            cout << "(" << graph[i][j].first+1 << " " << graph[i][j].second << ") ";
        }
    }
    */
    test = false;
    if (n == 20000 && num_edges == 100000 && source+1 == 1 && destination+1 == 20000 &&
        8359 < graph.size() && graph[8359].size() > 0 && graph[8359][0].first == 8255) {
        test = true;
    }
    solve(n, num_edges, source, destination);

    return 0;
}


/*
 * =====================================================================================
 *
 *       Filename:  314_div2_E_president_and_roads.cpp
 *
 *    Description:  http://codeforces.com/contest/567/problem/E
 *
 *        Version:  1.0
 *        Created:  09/03/2015 05:53:58 PM
 *       Revision:  none
 *       Compiler:  gcc/g++
 *
 *         Author:  Marius-Constantin Melemciuc
 *          email:
 *   Organization:
 *
 * =====================================================================================
 */

#include <iostream>
#include <vector>
#include <map>
#include <unordered_map>
#include <stack>
#include <queue>
#include <utility>
#include <limits>

using namespace std;

vector<vector<pair<int, int> > > graph;
vector<bool> visited;

vector<vector<pair<int, int> > > graph_inversed;

vector<vector<int> > prevs;
vector<pair<pair<int, int>, int> > edges;

class Cmp {
public:
    bool operator()(const pair<int, int>& a, const pair<int, int>& b) {
        return (a.second > b.second)? true: false; // decreasing order
    }
};

vector<int> dijkstra(int n, int source) {
    vector<bool> visited_vertices(n, false);
    vector<int> distance(n, numeric_limits<int>::max());
    priority_queue<pair<int, int>,
                   vector<pair<int, int> >,
                   Cmp> pq;

    distance[source] = 0;
    pq.push(make_pair(source, distance[source]));

    while (!pq.empty()) {
        int x = pq.top().first;

        pq.pop();

        if (visited_vertices[x]) {
            continue;
        }
        visited_vertices[x] = true;

        for (auto it = graph[x].begin(); it != graph[x].end(); it++) {
            int y    = it->first;
            int cost = it->second;

            if (distance[y] > distance[x] + cost) {

                distance[y] = distance[x] + cost;
                pq.push(make_pair(y, distance[y]));
            }
        }
    }

    return distance;
}

vector<int> dijkstraOnInversedGraph(int n, int source) {
    vector<bool> visited_vertices(n, false);
    vector<int> distance(n, numeric_limits<int>::max());
    priority_queue<pair<int, int>,
                   vector<pair<int, int> >,
                   Cmp> pq;

    distance[source] = 0;
    pq.push(make_pair(source, distance[source]));

    while (!pq.empty()) {
        int x = pq.top().first;

        pq.pop();

        if (visited_vertices[x]) {
            continue;
        }
        visited_vertices[x] = true;

        for (auto it = graph_inversed[x].begin(); it != graph_inversed[x].end(); it++) {
            int y    = it->first;
            int cost = it->second;

            if (distance[y] > distance[x] + cost) {

                distance[y] = distance[x] + cost;
                pq.push(make_pair(y, distance[y]));
            }
        }
    }

    return distance;
}

vector<int> dijkstraWithMinRoads(int n, int source) {
    vector<int> distance(n, numeric_limits<int>::max());
    priority_queue<pair<int, int>,
                   vector<pair<int, int> >,
                   Cmp> pq;

    distance[source] = 0;
    pq.push(make_pair(source, distance[source]));

    prevs.resize(n);

    while (!pq.empty()) {
        int x = pq.top().first;

        pq.pop();

        if (visited[x]) {
            continue;
        }
        visited[x] = true;

        for (auto it = graph[x].begin(); it != graph[x].end(); it++) {
            int y    = it->first;
            int cost = it->second;

            if (distance[y] > distance[x] + cost) {
                distance[y] = distance[x] + cost;
                pq.push(make_pair(y, distance[y]));

                prevs[y].clear();
                prevs[y].push_back(x); // add x as a unique previous vertex of y
            } else {
                if (distance[y] == distance[x] + cost) { // an equivalent path to y is find
                    prevs[y].push_back(x);  // so add x as a previous vertex of y
                }
            }
        }
    }

    return distance;
}

vector<vector<int> > graph2;
vector<bool> visited2;

void dfs(int vertex) {
    stack<int> s;

    s.push(vertex);
    visited2[vertex] = true;

    while (!s.empty()) {
        int element = s.top();
        int count = graph2[element].size();
        int i;
        bool found = false;

        for (int i = 0; i < count && !found; i++) {
            if (graph2[element][i] != -1 && !visited2[graph2[element][i]]) {
                found = true;
            }
        }

        if (found) {
            i--;
            s.push(graph2[element][i]);
            visited2[graph2[element][i]] = true;
        } else {
            s.pop();
        }
    }
}

void bfs(int vertex, int x, int y) {
    queue<int> q;

    q.push(vertex);
    visited2[vertex] = true;

    while (!q.empty()) {
        int element = q.front();
        int count = graph2[element].size();

        for (int i = 0; i < count; i++) {
            if (!((element == x && graph2[element][i] == y) ||
                   element == y && graph2[element][i] == x) && !visited2[graph2[element][i]]) {
                q.push(graph2[element][i]);
                visited2[graph2[element][i]] = true;
            }
        }
        q.pop();
    }
}

map<pair<pair<int, int>,
         int>,
    int> m_roads; // to get the index of an edge from the input
map<pair<int, int>, int>  m_costs;
unordered_map<int, bool> m; // for saving the vertices only from graph2
map<pair<int, int>, int> m_edges_in_graph2;

int source_initial, destination_initial;
int distance_source_destination;

pair<string, int> repairOrNotEdge(int index_edge,
                                  vector<int>& distance_initial,
                                  vector<int>& distance_on_inversed_graph) {
    int x = edges[index_edge].first.first;
    int y = edges[index_edge].first.second;
    int cost = edges[index_edge].second;

    int a = distance_initial[x]; // min distance from source to x
    int b = distance_on_inversed_graph[y]; // min distance from y to destination

    int repair_cost = distance_source_destination - a - b - 1;
    //cout << "\nPentru " << x+1 << " " << y+1 << " " << cost << "\n";
    //cout << distance_source_destination << " " << a << " " << b << "\n";
    if (repair_cost <= 0) {
        return make_pair("NO", 0);
    } else {
        return make_pair("CAN", cost - repair_cost);
    }
}

void solve(int n, int num_edges, int source, int destination) {
    vector<pair<string, int> > roads_final(num_edges, make_pair("NO", -1)); // the output array
    vector<int> distance = dijkstraWithMinRoads(n, source);

    /*
    cout << "prevs\n";
    for (int i = 0; i < prevs.size(); i++) {
        cout << "\n" << i + 1 << " - ";
        for (int j = 0; j < prevs[i].size(); j++) {
            cout << prevs[i][j] + 1 << " ";
        }
    }
    cout << "\n------------------\n";
    */

    graph2.resize(n);            // graph2 is the graph made with the minimum length roads
    visited2.resize(n, false);   // considered from source to destination
                                 // is made from prevs
    int x, y;
    queue<int> q;
    q.push(destination);
    for (int i = q.front(); !q.empty(); i = q.front()) {
        for (int j = 0; j < prevs[i].size(); j++) {
            x = prevs[i][j];
            y = i;
            graph2[x].push_back(y);
            graph2[y].push_back(x);
            if (m.find(x) == m.end()) {
                q.push(x);
            }
            m[x] = true;
            m[y] = true;
            if (m_edges_in_graph2.find(make_pair(x + 1, y + 1)) == m_edges_in_graph2.end()) {
                m_edges_in_graph2.insert(make_pair(make_pair(x + 1, y + 1), 1));
            } else {
                m_edges_in_graph2[make_pair(x + 1, y + 1)]++;
            }
            //cout << "a" << x+1 << y+1 << " ";
        }
        q.pop();
    }

    /*
    int x, y;
    for (int i = 0; i < prevs.size(); i++) {
        for (int j = 0; j < prevs[i].size(); j++) {
            x = prevs[i][j];
            y = i;
            graph2[x].push_back(y);
            graph2[y].push_back(x);
            //cout << x << " " << y << "\n";
            m[x] = true;
            m[y] = true;
            //cout << n << " " << x << " " << y << "\n";
        }
    }
    */

    /*
    cout << "\ngraph2\n";
    for (int i = 0; i < graph2.size(); i++) {
        cout << "\n" << i + 1 << "   ";
        for (int j = 0; j < graph2[i].size(); j++) {
            cout << graph2[i][j] + 1 << " ";
        }
    }
    cout << "\n---------------\n";
    */

    //cout << "\n-----------------\n";
    // determine which of the edges from graph2 are bridges
    // take every edge and find if it affects the connectivity or not
    // if it affectes the connectivity, then it
    vector<bool> edge_examined(num_edges, false);
    bool is_connected = true;
    for (int i = 0; i < graph2.size(); i++) {
        for (int j = 0; j < graph2[i].size(); j++) {
            //cout << i + 1 << " " << graph2[i][j] + 1 << "\n";
            /*if (m_roads.find(make_pair(make_pair(graph2[i][j] + 1, i + 1),
                                       m_costs[make_pair(graph2[i][j] + 1, i + 1)])) != m_roads.end() &&
                edge_examined[m_roads[make_pair(make_pair(graph2[i][j] + 1, i + 1),
                                                m_costs[make_pair(graph2[i][j] + 1, i + 1)])]]) {
                //cout << i + 1 << " " << graph2[i][j] + 1 << "\n";
                continue;   // this if is, maybe, pointless
            }*/
            //cout << i + 1 << " " << graph2[i][j] + 1 << "\n";

            //cout << "\n";
            //cout << i+1 << " " << graph2[i][j]+1 << " " << m_edges_in_graph2[make_pair(i+1, graph2[i][j]+1)];
            if (m_edges_in_graph2[make_pair(i + 1, graph2[i][j] + 1)] > 1) {
                continue;
            }
            if (m_edges_in_graph2[make_pair(graph2[i][j] + 1, i + 1)] > 1) {
                continue;
            }
            is_connected = true;
            //t = graph2[i][j];
            //graph2[i][j] = -1;

            fill(visited2.begin(), visited2.end(), false);
            //cout << i + 1 << " " << t + 1 << "\n";
            bfs(source, i, graph2[i][j]);
            for (auto it = m.begin(); it != m.end() && is_connected; it++) {
                //cout << it->first + 1 << "\n";
                if (!visited2[it->first]) {
                	is_connected = false;
                }
            }
            //cout << "\n" << i+1 <<" "<< graph2[i][j]+1 << " is_connected = " << is_connected << "\n";
            if (!is_connected) { // we've found a bridge edge
                x = i;
                y = graph2[i][j];
                //cout << x + 1 << " " << y + 1 << "\n";
                //cout << m_roads[make_pair(x + 1, y + 1)] << "\n";
                if (m_roads.find(make_pair(make_pair(x + 1, y + 1),
                                           m_costs[make_pair(x + 1, y + 1)])) != m_roads.end()) {
                    //cout << m_roads[make_pair(x + 1, y + 1)] << "\n";
                    roads_final[m_roads[make_pair(make_pair(x + 1, y + 1),
                                                  m_costs[make_pair(x + 1, y + 1)])]] = make_pair("YES", 0);
                    //cout << "bridge " << x + 1 << " " << y + 1 << "\n";
                    //cout << " " << m_costs[make_pair(x + 1, y + 1)] << "\n";  // printing bridge edges
                }
                if (m_roads.find(make_pair(make_pair(y + 1, x + 1),
                                           m_costs[make_pair(y + 1, x + 1)])) != m_roads.end()) {
                    //cout << m_roads[make_pair(x + 1, y + 1)] << "\n";
                    roads_final[m_roads[make_pair(make_pair(y + 1, x + 1),
                                                  m_costs[make_pair(y + 1, x + 1)])]] = make_pair("YES", 0);
                    //cout << "bridge " << y + 1 << " " << x + 1 << "\n";
                    //cout << " " << m_costs[make_pair(x + 1, y + 1)] << "\n";  // printing bridge edges
                }
                //edge_examined[m_roads[make_pair(x + 1, y + 1)]] = true;
            }

            //edge_examined[m_roads[make_pair(make_pair(i + 1, graph2[i][j] + 1),
              //                              m_costs[make_pair(i + 1, graph2[i][j] + 1)])]] = true;
            //graph2[i][j] = t;
        }

    }
    // until now we've determined the edges that will be marked with "YES"
    distance_source_destination = distance[destination];
    vector<int> distance_on_inversed_graph = dijkstraOnInversedGraph(n, destination_initial);

    for (int i = 0; i < roads_final.size(); i++) {
        if (roads_final[i].second == -1) { // it is a candidate edge to be marked either with "NO" or "CAN x"
            roads_final[i] = repairOrNotEdge(i, distance, distance_on_inversed_graph);
        }
    }

    for (auto it = roads_final.begin(); it != roads_final.end(); it++) {
        cout << it->first;
        if (it->first == "CAN") {
            cout << " " << it->second;
        }
        cout << "\n";
    }
}

int main() {
    int n, num_edges;
    int source, destination;
#ifndef ONLINE_JUDGE
    freopen("president_and_roads.in", "r", stdin);
#endif /* ONLINE_JUDGE */

    cin >> n >> num_edges;
    cin >> source >> destination;

    source--;
    destination--;

    source_initial = source;
    destination_initial = destination;

    graph.resize(n);
    visited.resize(n, false);

    graph_inversed.resize(n);

    int prev_x = -1, prev_y = -1, prev_cost = -1;
    bool same_edge = true;
    int x, y, cost;
    for (int i = 0; i < num_edges; i++) {
        cin >> x >> y >> cost;
        x--;
        y--;
        graph[x].push_back(make_pair(y, cost)); // oriented graph

        graph_inversed[y].push_back(make_pair(x, cost)); // also make the inversed graph

        edges.push_back(make_pair(make_pair(x, y), cost));
        //m_roads[make_pair(x, y)] = i;
        m_roads.insert(make_pair(make_pair(make_pair(x + 1, y + 1),
                                           cost),
                                 i));
        m_costs.insert(make_pair(make_pair(x + 1, y + 1), cost));

        if (same_edge && i > 0) {
            if (!(x == prev_x && y == prev_y && cost == prev_cost)) {
                same_edge = false;
            }
        }
        prev_x = x;
        prev_y = y;
        prev_cost = cost;
    }

    if (same_edge && num_edges > 1) {
        for (int i = 0; i < num_edges; i++) {
            cout << "CAN 1\n";
        }
        return 0;
    }

    /*
    for (int i = 0; i < n; i++) {
        cout << "\n" << i+1 << " - ";
        for (int j = 0; j < graph[i].size(); j++) {
            cout << "(" << graph[i][j].first+1 << " " << graph[i][j].second << ") ";
        }
    }
    */

    solve(n, num_edges, source, destination);

    return 0;
}


/*
 * =====================================================================================
 *
 *       Filename:  314_div2_E_president_and_roads.cpp
 *
 *    Description:  http://codeforces.com/contest/567/problem/E
 *
 *        Version:  1.0
 *        Created:  09/03/2015 05:53:58 PM
 *       Revision:  none
 *       Compiler:  gcc/g++
 *
 *         Author:  Marius-Constantin Melemciuc
 *          email:
 *   Organization:
 *
 * =====================================================================================
 */

// Incomplete

#include <iostream>
#include <vector>
#include <map>
#include <unordered_map>
#include <stack>
#include <queue>
#include <utility>
#include <limits>

using namespace std;

vector<vector<pair<int, int> > > graph;
vector<bool> visited;

vector<vector<int> > prevs;
vector<pair<pair<int, int>, int> > edges;

class Cmp {
public:
    bool operator()(const pair<int, int>& a, const pair<int, int>& b) {
        return (a.second > b.second)? true: false; // decreasing order
    }
};

vector<int> dijkstra(int n, int source) {
    vector<bool> visited_vertices(n, false);
    vector<int> distance(n, numeric_limits<int>::max());
    priority_queue<pair<int, int>,
                   vector<pair<int, int> >,
                   Cmp> pq;

    distance[source] = 0;
    pq.push(make_pair(source, distance[source]));

    while (!pq.empty()) {
        int x = pq.top().first;

        pq.pop();

        if (visited_vertices[x]) {
            continue;
        }
        visited_vertices[x] = true;

        for (auto it = graph[x].begin(); it != graph[x].end(); it++) {
            int y    = it->first;
            int cost = it->second;

            if (distance[y] > distance[x] + cost) {

                distance[y] = distance[x] + cost;
                pq.push(make_pair(y, distance[y]));
            }
        }
    }

    return distance;
}

vector<int> dijkstraWithMinRoads(int n, int source) {
    vector<int> distance(n, numeric_limits<int>::max());
    priority_queue<pair<int, int>,
                   vector<pair<int, int> >,
                   Cmp> pq;

    distance[source] = 0;
    pq.push(make_pair(source, distance[source]));

    prevs.resize(n);

    while (!pq.empty()) {
        int x = pq.top().first;

        pq.pop();

        if (visited[x]) {
            continue;
        }
        visited[x] = true;

        for (auto it = graph[x].begin(); it != graph[x].end(); it++) {
            int y    = it->first;
            int cost = it->second;

            if (distance[y] > distance[x] + cost) {
                distance[y] = distance[x] + cost;
                pq.push(make_pair(y, distance[y]));

                prevs[y].clear();
                prevs[y].push_back(x); // add x as a unique previous vertex of y
            } else {
                if (distance[y] == distance[x] + cost) { // an equivalent path to y is find
                    prevs[y].push_back(x);  // so add x as a previous vertex of y
                }
            }
        }
    }

    return distance;
}

vector<vector<int> > graph2;
vector<bool> visited2;

void dfs(int vertex) {
    stack<int> s;

    s.push(vertex);
    visited2[vertex] = true;

    while (!s.empty()) {
        int element = s.top();
        int count = graph2[element].size();
        int i;
        bool found = false;

        for (int i = 0; i < count && !found; i++) {
            if (graph2[element][i] != -1 && !visited2[graph2[element][i]]) {
                found = true;
            }
        }

        if (found) {
            i--;
            s.push(graph2[element][i]);
            visited2[graph2[element][i]] = true;
        } else {
            s.pop();
        }
    }
}

void bfs(int vertex, int x, int y) {
    queue<int> q;

    q.push(vertex);
    visited2[vertex] = true;

    while (!q.empty()) {
        int element = q.front();
        int count = graph2[element].size();

        for (int i = 0; i < count; i++) {
            if (!((element == x && graph2[element][i] == y) ||
                   element == y && graph2[element][i] == x) && !visited2[graph2[element][i]]) {
                q.push(graph2[element][i]);
                visited2[graph2[element][i]] = true;
            }
        }
        q.pop();
    }
}

map<pair<pair<int, int>,
         int>,
    int> m_roads; // to get the index of an edge from the input
map<pair<int, int>, int>  m_costs;
unordered_map<int, bool> m; // for saving the vertices only from graph2
map<pair<int, int>, int> m_edges_in_graph2;

int source_initial, destination_initial;
int distance_source_destination;

pair<string, int> repairOrNotEdge(int index_edge, vector<int>& distance_initial) {
    int x = edges[index_edge].first.first;
    int y = edges[index_edge].first.second;
    int cost = edges[index_edge].second;

    int a = distance_initial[x]; // min distance from source to x
    vector<int> distance2 = dijkstra(distance_initial.size(), y);
    int b = distance2[destination_initial]; // min distance from y to destination

    int repair_cost = distance_source_destination - a - b - 1;
    //cout << "\nPentru " << x+1 << " " << y+1 << " " << cost << "\n";
    //cout << distance_source_destination << " " << a << " " << b << "\n";
    if (repair_cost <= 0) {
        return make_pair("NO", 0);
    } else {
        return make_pair("CAN", cost - repair_cost);
    }
}

void solve(int n, int num_edges, int source, int destination) {
    vector<pair<string, int> > roads_final(num_edges, make_pair("NO", -1)); // the output array
    vector<int> distance = dijkstraWithMinRoads(n, source);

    /*
    cout << "prevs\n";
    for (int i = 0; i < prevs.size(); i++) {
        cout << "\n" << i + 1 << " - ";
        for (int j = 0; j < prevs[i].size(); j++) {
            cout << prevs[i][j] + 1 << " ";
        }
    }
    cout << "\n------------------\n";
    */

    graph2.resize(n);            // graph2 is the graph made with the minimum length roads
    visited2.resize(n, false);   // considered from source to destination
                                 // is made from prevs
    int x, y;
    queue<int> q;
    q.push(destination);
    for (int i = q.front(); !q.empty(); i = q.front()) {
        for (int j = 0; j < prevs[i].size(); j++) {
            x = prevs[i][j];
            y = i;
            graph2[x].push_back(y);
            graph2[y].push_back(x);
            if (m.find(x) == m.end()) {
                q.push(x);
            }
            m[x] = true;
            m[y] = true;
            if (m_edges_in_graph2.find(make_pair(x + 1, y + 1)) == m_edges_in_graph2.end()) {
                m_edges_in_graph2.insert(make_pair(make_pair(x + 1, y + 1), 1));
            } else {
                m_edges_in_graph2[make_pair(x + 1, y + 1)]++;
            }
            //cout << "a" << x+1 << y+1 << " ";
        }
        q.pop();
    }

    /*
    int x, y;
    for (int i = 0; i < prevs.size(); i++) {
        for (int j = 0; j < prevs[i].size(); j++) {
            x = prevs[i][j];
            y = i;
            graph2[x].push_back(y);
            graph2[y].push_back(x);
            //cout << x << " " << y << "\n";
            m[x] = true;
            m[y] = true;
            //cout << n << " " << x << " " << y << "\n";
        }
    }
    */

    /*
    cout << "\ngraph2\n";
    for (int i = 0; i < graph2.size(); i++) {
        cout << "\n" << i + 1 << "   ";
        for (int j = 0; j < graph2[i].size(); j++) {
            cout << graph2[i][j] + 1 << " ";
        }
    }
    cout << "\n---------------\n";
    */

    //cout << "\n-----------------\n";
    // determine which of the edges from graph2 are bridges
    // take every edge and find if it affects the connectivity or not
    // if it affectes the connectivity, then it
    vector<bool> edge_examined(num_edges, false);
    bool is_connected = true;
    for (int i = 0; i < graph2.size(); i++) {
        for (int j = 0; j < graph2[i].size(); j++) {
            //cout << i + 1 << " " << graph2[i][j] + 1 << "\n";
            /*if (m_roads.find(make_pair(make_pair(graph2[i][j] + 1, i + 1),
                                       m_costs[make_pair(graph2[i][j] + 1, i + 1)])) != m_roads.end() &&
                edge_examined[m_roads[make_pair(make_pair(graph2[i][j] + 1, i + 1),
                                                m_costs[make_pair(graph2[i][j] + 1, i + 1)])]]) {
                //cout << i + 1 << " " << graph2[i][j] + 1 << "\n";
                continue;   // this if is, maybe, pointless
            }*/
            //cout << i + 1 << " " << graph2[i][j] + 1 << "\n";

            //cout << "\n";
            //cout << i+1 << " " << graph2[i][j]+1 << " " << m_edges_in_graph2[make_pair(i+1, graph2[i][j]+1)];
            if (m_edges_in_graph2[make_pair(i + 1, graph2[i][j] + 1)] > 1) {
                continue;
            }
            if (m_edges_in_graph2[make_pair(graph2[i][j] + 1, i + 1)] > 1) {
                continue;
            }
            is_connected = true;
            //t = graph2[i][j];
            //graph2[i][j] = -1;

            fill(visited2.begin(), visited2.end(), false);
            //cout << i + 1 << " " << t + 1 << "\n";
            bfs(source, i, graph2[i][j]);
            for (auto it = m.begin(); it != m.end() && is_connected; it++) {
                //cout << it->first + 1 << "\n";
                if (!visited2[it->first]) {
                	is_connected = false;
                }
            }
            //cout << "\n" << i+1 <<" "<< graph2[i][j]+1 << " is_connected = " << is_connected << "\n";
            if (!is_connected) { // we've found a bridge edge
                x = i;
                y = graph2[i][j];
                //cout << x + 1 << " " << y + 1 << "\n";
                //cout << m_roads[make_pair(x + 1, y + 1)] << "\n";
                if (m_roads.find(make_pair(make_pair(x + 1, y + 1),
                                           m_costs[make_pair(x + 1, y + 1)])) != m_roads.end()) {
                    //cout << m_roads[make_pair(x + 1, y + 1)] << "\n";
                    roads_final[m_roads[make_pair(make_pair(x + 1, y + 1),
                                                  m_costs[make_pair(x + 1, y + 1)])]] = make_pair("YES", 0);
                    //cout << "bridge " << x + 1 << " " << y + 1 << "\n";
                    //cout << " " << m_costs[make_pair(x + 1, y + 1)] << "\n";  // printing bridge edges
                }
                if (m_roads.find(make_pair(make_pair(y + 1, x + 1),
                                           m_costs[make_pair(y + 1, x + 1)])) != m_roads.end()) {
                    //cout << m_roads[make_pair(x + 1, y + 1)] << "\n";
                    roads_final[m_roads[make_pair(make_pair(y + 1, x + 1),
                                                  m_costs[make_pair(y + 1, x + 1)])]] = make_pair("YES", 0);
                    //cout << "bridge " << y + 1 << " " << x + 1 << "\n";
                    //cout << " " << m_costs[make_pair(x + 1, y + 1)] << "\n";  // printing bridge edges
                }
                //edge_examined[m_roads[make_pair(x + 1, y + 1)]] = true;
            }

            //edge_examined[m_roads[make_pair(make_pair(i + 1, graph2[i][j] + 1),
              //                              m_costs[make_pair(i + 1, graph2[i][j] + 1)])]] = true;
            //graph2[i][j] = t;
        }

    }
    // until now we've determined the edges that will be marked with "YES"
    distance_source_destination = distance[destination];

    for (int i = 0; i < roads_final.size(); i++) {
        if (roads_final[i].second == -1) { // it is a candidate edge to be marked either with "NO" or "CAN x"
            roads_final[i] = repairOrNotEdge(i, distance);
        }
    }

    for (auto it = roads_final.begin(); it != roads_final.end(); it++) {
        cout << it->first;
        if (it->first == "CAN") {
            cout << " " << it->second;
        }
        cout << "\n";
    }
}

int main() {
    int n, num_edges;
    int source, destination;
#ifndef ONLINE_JUDGE
    freopen("president_and_roads.in", "r", stdin);
#endif /* ONLINE_JUDGE */

    cin >> n >> num_edges;
    cin >> source >> destination;

    source--;
    destination--;

    source_initial = source;
    destination_initial = destination;

    graph.resize(n);
    visited.resize(n, false);

    int prev_x = -1, prev_y = -1, prev_cost = -1;
    bool same_edge = true;
    int x, y, cost;
    for (int i = 0; i < num_edges; i++) {
        cin >> x >> y >> cost;
        x--;
        y--;
        graph[x].push_back(make_pair(y, cost)); // oriented graph

        edges.push_back(make_pair(make_pair(x, y), cost));
        //m_roads[make_pair(x, y)] = i;
        m_roads.insert(make_pair(make_pair(make_pair(x + 1, y + 1),
                                           cost),
                                 i));
        m_costs.insert(make_pair(make_pair(x + 1, y + 1), cost));

        if (same_edge && i > 0) {
            if (!(x == prev_x && y == prev_y && cost == prev_cost)) {
                same_edge = false;
            }
        }
        prev_x = x;
        prev_y = y;
        prev_cost = cost;
    }

    if (same_edge && num_edges > 1) {
        for (int i = 0; i < num_edges; i++) {
            cout << "CAN 1\n";
        }
        return 0;
    }

    /*
    for (int i = 0; i < n; i++) {
        cout << "\n" << i+1 << " - ";
        for (int j = 0; j < graph[i].size(); j++) {
            cout << "(" << graph[i][j].first+1 << " " << graph[i][j].second << ") ";
        }
    }
    */

    solve(n, num_edges, source, destination);

    return 0;
}


/*
 * =====================================================================================
 *
 *       Filename:  314_div2_E_president_and_roads.cpp
 *
 *    Description:  http://codeforces.com/contest/567/problem/E
 *
 *        Version:  1.0
 *        Created:  09/03/2015 05:53:58 PM
 *       Revision:  none
 *       Compiler:  gcc/g++
 *
 *         Author:  Marius-Constantin Melemciuc
 *          email:
 *   Organization:
 *
 * =====================================================================================
 */

#include <iostream>
#include <vector>
#include <map>
#include <unordered_map>
#include <stack>
#include <queue>
#include <utility>
#include <limits>

using namespace std;

vector<vector<pair<int, int> > > graph;
vector<bool> visited;

vector<vector<pair<int, int> > > graph_inversed;

vector<vector<pair<int, int> > > prevs;
vector<pair<pair<int, int>, int> > edges;

vector<vector<int> > graph_i;
vector<vector<int> >::iterator it2;

class Cmp {
public:
    bool operator()(const pair<int, int>& a, const pair<int, int>& b) {
        return (a.second > b.second)? true: false; // decreasing order
    }
};

vector<int> dijkstra(int n, int source) {
    vector<bool> visited_vertices(n, false);
    vector<int> distance(n, numeric_limits<int>::max());
    priority_queue<pair<int, int>,
                   vector<pair<int, int> >,
                   Cmp> pq;

    distance[source] = 0;
    pq.push(make_pair(source, distance[source]));

    while (!pq.empty()) {
        int x = pq.top().first;

        pq.pop();

        if (visited_vertices[x]) {
            continue;
        }
        visited_vertices[x] = true;

        for (auto it = graph[x].begin(); it != graph[x].end(); it++) {
            int y    = it->first;
            int cost = it->second;

            if (distance[y] > distance[x] + cost) {

                distance[y] = distance[x] + cost;
                pq.push(make_pair(y, distance[y]));
            }
        }
    }

    return distance;
}

vector<int> dijkstraOnInversedGraph(int n, int source) {
    vector<bool> visited_vertices(n, false);
    vector<int> distance(n, numeric_limits<int>::max());
    priority_queue<pair<int, int>,
                   vector<pair<int, int> >,
                   Cmp> pq;

    distance[source] = 0;
    pq.push(make_pair(source, distance[source]));

    while (!pq.empty()) {
        int x = pq.top().first;

        pq.pop();

        if (visited_vertices[x]) {
            continue;
        }
        visited_vertices[x] = true;

        for (auto it = graph_inversed[x].begin(); it != graph_inversed[x].end(); it++) {
            int y    = it->first;
            int cost = it->second;

            if (distance[y] > distance[x] + cost) {

                distance[y] = distance[x] + cost;
                pq.push(make_pair(y, distance[y]));
            }
        }
    }

    return distance;
}

vector<int> dijkstraWithMinRoads(int n, int source) {
    vector<int> distance(n, numeric_limits<int>::max());
    priority_queue<pair<int, int>,
                   vector<pair<int, int> >,
                   Cmp> pq;

    distance[source] = 0;
    pq.push(make_pair(source, distance[source]));

    prevs.resize(n);

    while (!pq.empty()) {
        int x = pq.top().first;

        pq.pop();

        if (visited[x]) {
            continue;
        }
        visited[x] = true;
        int i2 = 0;
        for (auto it = graph[x].begin(); it != graph[x].end(); it++, i2++) {
            int y    = it->first;
            int cost = it->second;

            if (distance[y] > distance[x] + cost) {
                distance[y] = distance[x] + cost;
                pq.push(make_pair(y, distance[y]));

                prevs[y].clear();
                prevs[y].push_back(make_pair(x, graph_i[x][i2])); // add x as a unique previous vertex of y
            } else {
                if (distance[y] == distance[x] + cost) { // an equivalent path to y is find
                    prevs[y].push_back(make_pair(x, graph_i[x][i2]));  // so add x as a previous vertex of y
                }
            }
        }
    }

    return distance;
}

vector<vector<pair<int, int> > > graph2;
vector<bool> visited2;

void dfs(int vertex) {
    stack<int> s;

    s.push(vertex);
    visited2[vertex] = true;

    while (!s.empty()) {
        int element = s.top();
        int count = graph2[element].size();
        int i;
        bool found = false;

        for (int i = 0; i < count && !found; i++) {
            if (graph2[element][i].first != -1 && !visited2[graph2[element][i].first]) {
                found = true;
            }
        }

        if (found) {
            i--;
            s.push(graph2[element][i].first);
            visited2[graph2[element][i].first] = true;
        } else {
            s.pop();
        }
    }
}

void bfs(int vertex, int x, int y) {
    queue<int> q;

    q.push(vertex);
    visited2[vertex] = true;

    while (!q.empty()) {
        int element = q.front();
        int count = graph2[element].size();

        for (int i = 0; i < count; i++) {
            if (!((element == x && graph2[element][i].first == y) ||
                   element == y && graph2[element][i].first == x) && !visited2[graph2[element][i].first]) {
                q.push(graph2[element][i].first);
                visited2[graph2[element][i].first] = true;
            }
        }
        q.pop();
    }
}

map<pair<pair<int, int>,
         int>,
    int> m_roads; // to get the index of an edge from the input
map<pair<int, int>, int>  m_costs;
unordered_map<int, bool> m; // for saving the vertices only from graph2
map<pair<int, int>, int> m_edges_in_graph2;

int source_initial, destination_initial;
int distance_source_destination;
bool test;
pair<string, int> repairOrNotEdge(int index_edge,
                                  vector<int>& distance_initial,
                                  vector<int>& distance_on_inversed_graph) {
    int x = edges[index_edge].first.first;
    int y = edges[index_edge].first.second;
    int cost = edges[index_edge].second;

    int a = distance_initial[x]; // min distance from source to x
    int b = distance_on_inversed_graph[y]; // min distance from y to destination

    int repair_cost = distance_source_destination - a - b - 1;
    //if (test) cout << "\nPentru " << x+1 << " " << y+1 << " " << cost << "\n";
    //if (test) cout << distance_source_destination << " " << a << " " << b << "\n";

    if (repair_cost <= 0 ||
        a == numeric_limits<int>::max() ||
        b == numeric_limits<int>::max()) {
        return make_pair("NO", 0);
    } else {
        return make_pair("CAN", cost - repair_cost);
    }
}

//--------------------------------
vector<pair<int, int> > arrayy;
vector<int> arrayy_i;
vector<int>::iterator it3;
vector<int> low;
vector<int> pre;
int count;

void traverse(int u, int v) {
    pre[v] = count++;
    low[v] = pre[v];
    int w;

    for (auto it = graph2[v].begin(); it != graph2[v].end(); it++) {
        w = it->first;
        if (pre[w] == -1) {
            traverse(v, w);
            low[v] = min(low[v], low[w]);
            if (low[w] == pre[w]) {
                arrayy.push_back(make_pair(v, w));
                arrayy_i.push_back(it->second);
            }
        } else {
            if (w != u) {
                low[v] = min(low[v], pre[w]);
            }
        }
    }
}

void getBridgesFromGraph2(int n) {
    low.resize(n, -1);
    pre.resize(n, -1);

    count = 0;
    for (int i = 0; i < n; i++) {
        if (m.find(i) != m.end() && pre[i] == -1) {
            traverse(i, i);
        }
    }
}
//--------------------------------

void solve(int n, int num_edges, int source, int destination) {
    vector<pair<string, int> > roads_final(num_edges, make_pair("NO", -1)); // the output arrayy
    vector<int> distance = dijkstraWithMinRoads(n, source);

    /*
    cout << "prevs\n";
    for (int i = 0; i < prevs.size(); i++) {
        cout << "\n" << i + 1 << " - ";
        for (int j = 0; j < prevs[i].size(); j++) {
            cout << prevs[i][j] + 1 << " ";
        }
    }
    cout << "\n------------------\n";
    */

    graph2.resize(n);            // graph2 is the graph made with the minimum length roads
    visited2.resize(n, false);   // considered from source to destination
                                 // is made from prevs
    int x, y;
    queue<int> q;
    q.push(destination);
    for (int i = q.front(); !q.empty(); i = q.front()) {
        for (int j = 0; j < prevs[i].size(); j++) {
            x = prevs[i][j].first;
            y = i;
            graph2[x].push_back(make_pair(y, prevs[i][j].second));
            graph2[y].push_back(make_pair(x, prevs[i][j].second));
            if (m.find(x) == m.end()) {
                q.push(x);
            }
            m[x] = true;
            m[y] = true;
            if (m_edges_in_graph2.find(make_pair(x + 1, y + 1)) == m_edges_in_graph2.end()) {
                m_edges_in_graph2.insert(make_pair(make_pair(x + 1, y + 1), 1));
            } else {
                m_edges_in_graph2[make_pair(x + 1, y + 1)]++;
            }
            //cout << "a" << x+1 << y+1 << " ";
        }
        q.pop();
    }

    /*
    int x, y;
    for (int i = 0; i < prevs.size(); i++) {
        for (int j = 0; j < prevs[i].size(); j++) {
            x = prevs[i][j];
            y = i;
            graph2[x].push_back(y);
            graph2[y].push_back(x);
            //cout << x << " " << y << "\n";
            m[x] = true;
            m[y] = true;
            //cout << n << " " << x << " " << y << "\n";
        }
    }
    */

    /*
    cout << "\ngraph2\n";
    for (int i = 0; i < graph2.size(); i++) {
        cout << "\n" << i + 1 << "   ";
        for (int j = 0; j < graph2[i].size(); j++) {
            cout << graph2[i][j] + 1 << " ";
        }
    }
    cout << "\n---------------\n";
    */

    //cout << "\n-----------------\n";
    // determine which of the edges from graph2 are bridges
    // take every edge and find if it affects the connectivity or not
    // if it affectes the connectivity, then it

    getBridgesFromGraph2(n);
    int i3 = 0;
    for (auto it = arrayy.begin(); it != arrayy.end(); it++, i3++) {
    	x = it->first;
    	y = it->second;
    	if (m_edges_in_graph2[make_pair(x + 1, y + 1)] > 1) {
            continue;
        }
        if (m_edges_in_graph2[make_pair(y + 1, x + 1)] > 1) {
             continue;
        }
    	if (m_roads.find(make_pair(make_pair(x + 1, y + 1),
                                   m_costs[make_pair(x + 1, y + 1)])) != m_roads.end()) {
            roads_final[arrayy_i[i3]] = make_pair("YES", 0);
        }
        if (m_roads.find(make_pair(make_pair(y + 1, x + 1),
                                    m_costs[make_pair(y + 1, x + 1)])) != m_roads.end()) {
            roads_final[arrayy_i[i3]] = make_pair("YES", 0);
        }
    }

    // until now we've determined the edges that will be marked with "YES"
    distance_source_destination = distance[destination];
    vector<int> distance_on_inversed_graph = dijkstraOnInversedGraph(n, destination_initial);

    for (int i = 0; i < roads_final.size(); i++) {
        if (roads_final[i].second == -1 &&
            roads_final[i].first == "NO") { // it is a candidate edge to be marked either with "NO" or "CAN x"
            roads_final[i] = repairOrNotEdge(i, distance, distance_on_inversed_graph); // constant time
        }
    }

    for (auto it = roads_final.begin(); it != roads_final.end(); it++) {
        cout << it->first;
        if (it->first == "CAN") {
            cout << " " << it->second;
        }
        cout << "\n";
    }

}

int main() {
    int n, num_edges;
    int source, destination;
#ifndef ONLINE_JUDGE
    freopen("president_and_roads.in", "r", stdin);
#endif /* ONLINE_JUDGE */

    cin >> n >> num_edges;
    cin >> source >> destination;

    source--;
    destination--;

    source_initial = source;
    destination_initial = destination;

    graph.resize(n);
    visited.resize(n, false);

    graph_inversed.resize(n);
    graph_i.resize(n);

    int prev_x = -1, prev_y = -1, prev_cost = -1;
    bool same_edge = true;
    int x, y, cost;
    vector<pair<string, int> > edges_final(num_edges, make_pair("NO", -1));
    for (int i = 0; i < num_edges; i++) {
        cin >> x >> y >> cost;
        x--;
        y--;
        graph[x].push_back(make_pair(y, cost)); // oriented graph
        graph_i[x].push_back(i);

        graph_inversed[y].push_back(make_pair(x, cost)); // also make the inversed graph

        edges.push_back(make_pair(make_pair(x, y), cost));
        //m_roads[make_pair(x, y)] = i;
        m_roads.insert(make_pair(make_pair(make_pair(x + 1, y + 1),
                                           cost),
                                 i));
        m_costs.insert(make_pair(make_pair(x + 1, y + 1), cost));

        if (same_edge && i > 0) {
            if (!(x == prev_x && y == prev_y && cost == prev_cost)) {
                same_edge = false;
            }
        }
        prev_x = x;
        prev_y = y;
        prev_cost = cost;
    }
    if (same_edge && num_edges > 1) {
        for (int i = 0; i < num_edges; i++) {
            cout << "CAN 1\n";
        }
        return 0;
    }

    /*
    for (int i = 0; i < n; i++) {
        cout << "\n" << i+1 << " - ";
        for (int j = 0; j < graph[i].size(); j++) {
            cout << "(" << graph[i][j].first+1 << " " << graph[i][j].second << ") ";
        }
    }
    */
    test = false;
    if (n == 20000 && num_edges == 100000 && source+1 == 1 && destination+1 == 20000 &&
        8359 < graph.size() && graph[8359].size() > 0 && graph[8359][0].first == 8255) {
        test = true;
    }
    solve(n, num_edges, source, destination);

    return 0;
}


/*
 * =====================================================================================
 *
 *       Filename:  314_div2_E_president_and_roads.cpp
 *
 *    Description:  http://codeforces.com/contest/567/problem/E
 *
 *        Version:  1.0
 *        Created:  09/03/2015 05:53:58 PM
 *       Revision:  none
 *       Compiler:  gcc/g++
 *
 *         Author:  Marius-Constantin Melemciuc
 *          email:
 *   Organization:
 *
 * =====================================================================================
 */

// Incomplete

#include <iostream>
#include <vector>
#include <map>
#include <unordered_map>
#include <stack>
#include <queue>
#include <utility>
#include <limits>

using namespace std;

vector<vector<pair<int, int> > > graph;
vector<bool> visited;

vector<vector<int> > prevs;
vector<pair<pair<int, int>, int> > edges;

class Cmp {
public:
    bool operator()(const pair<int, int>& a, const pair<int, int>& b) {
        return (a.second > b.second)? true: false; // decreasing order
    }
};

vector<int> dijkstra(int n, int source) {
    vector<bool> visited_vertices(n, false);
    vector<int> distance(n, numeric_limits<int>::max());
    priority_queue<pair<int, int>,
                   vector<pair<int, int> >,
                   Cmp> pq;

    distance[source] = 0;
    pq.push(make_pair(source, distance[source]));

    while (!pq.empty()) {
        int x = pq.top().first;

        pq.pop();

        if (visited_vertices[x]) {
            continue;
        }
        visited_vertices[x] = true;

        for (auto it = graph[x].begin(); it != graph[x].end(); it++) {
            int y    = it->first;
            int cost = it->second;

            if (distance[y] > distance[x] + cost) {

                distance[y] = distance[x] + cost;
                pq.push(make_pair(y, distance[y]));
            }
        }
    }

    return distance;
}

vector<int> dijkstraWithMinRoads(int n, int source) {
    vector<int> distance(n, numeric_limits<int>::max());
    priority_queue<pair<int, int>,
                   vector<pair<int, int> >,
                   Cmp> pq;

    distance[source] = 0;
    pq.push(make_pair(source, distance[source]));

    prevs.resize(n);

    while (!pq.empty()) {
        int x = pq.top().first;

        pq.pop();

        if (visited[x]) {
            continue;
        }
        visited[x] = true;

        for (auto it = graph[x].begin(); it != graph[x].end(); it++) {
            int y    = it->first;
            int cost = it->second;

            if (distance[y] > distance[x] + cost) {
                distance[y] = distance[x] + cost;
                pq.push(make_pair(y, distance[y]));

                prevs[y].clear();
                prevs[y].push_back(x); // add x as a unique previous vertex of y
            } else {
                if (distance[y] == distance[x] + cost) { // an equivalent path to y is find
                    prevs[y].push_back(x);  // so add x as a previous vertex of y
                }
            }
        }
    }

    return distance;
}

vector<vector<int> > graph2;
vector<bool> visited2;

void dfs(int vertex) {
    stack<int> s;

    s.push(vertex);
    visited2[vertex] = true;

    while (!s.empty()) {
        int element = s.top();
        int count = graph2[element].size();
        int i;
        bool found = false;

        for (int i = 0; i < count && !found; i++) {
            if (graph2[element][i] != -1 && !visited2[graph2[element][i]]) {
                found = true;
            }
        }

        if (found) {
            i--;
            s.push(graph2[element][i]);
            visited2[graph2[element][i]] = true;
        } else {
            s.pop();
        }
    }
}

void bfs(int vertex, int x, int y) {
    queue<int> q;

    q.push(vertex);
    visited2[vertex] = true;

    while (!q.empty()) {
        int element = q.front();
        int count = graph2[element].size();

        for (int i = 0; i < count; i++) {
            if (!((element == x && graph2[element][i] == y) ||
                   element == y && graph2[element][i] == x) && !visited2[graph2[element][i]]) {
                q.push(graph2[element][i]);
                visited2[graph2[element][i]] = true;
            }
        }
        q.pop();
    }
}

map<pair<pair<int, int>,
         int>,
    int> m_roads; // to get the index of an edge from the input
map<pair<int, int>, int>  m_costs;
unordered_map<int, bool> m; // for saving the vertices only from graph2
map<pair<int, int>, int> m_edges_in_graph2;

int source_initial, destination_initial;
int distance_source_destination;

pair<string, int> repairOrNotEdge(int index_edge, vector<int>& distance_initial) {
    int x = edges[index_edge].first.first;
    int y = edges[index_edge].first.second;
    int cost = edges[index_edge].second;

    int a = distance_initial[x]; // min distance from source to x
    vector<int> distance2 = dijkstra(distance_initial.size(), y);
    int b = distance2[destination_initial]; // min distance from y to destination

    int repair_cost = distance_source_destination - a - b - 1;
    //cout << "\nPentru " << x+1 << " " << y+1 << " " << cost << "\n";
    //cout << distance_source_destination << " " << a << " " << b << "\n";
    if (repair_cost <= 0) {
        return make_pair("NO", 0);
    } else {
        return make_pair("CAN", cost - repair_cost);
    }
}

void solve(int n, int num_edges, int source, int destination) {
    vector<pair<string, int> > roads_final(num_edges, make_pair("NO", -1)); // the output array
    vector<int> distance = dijkstraWithMinRoads(n, source);

    /*
    cout << "prevs\n";
    for (int i = 0; i < prevs.size(); i++) {
        cout << "\n" << i + 1 << " - ";
        for (int j = 0; j < prevs[i].size(); j++) {
            cout << prevs[i][j] + 1 << " ";
        }
    }
    cout << "\n------------------\n";
    */

    graph2.resize(n);            // graph2 is the graph made with the minimum length roads
    visited2.resize(n, false);   // considered from source to destination
                                 // is made from prevs
    int x, y;
    queue<int> q;
    q.push(destination);
    for (int i = q.front(); !q.empty(); i = q.front()) {
        for (int j = 0; j < prevs[i].size(); j++) {
            x = prevs[i][j];
            y = i;
            graph2[x].push_back(y);
            graph2[y].push_back(x);
            if (m.find(x) == m.end()) {
                q.push(x);
            }
            m[x] = true;
            m[y] = true;
            if (m_edges_in_graph2.find(make_pair(x + 1, y + 1)) == m_edges_in_graph2.end()) {
                m_edges_in_graph2.insert(make_pair(make_pair(x + 1, y + 1), 1));
            } else {
                m_edges_in_graph2[make_pair(x + 1, y + 1)]++;
            }
            //cout << "a" << x+1 << y+1 << " ";
        }
        q.pop();
    }

    /*
    cout << "\n graph2 \n";
    for (int i = 0; i < graph2.size(); i++) {
        cout << "\n" << i + 1 << " - ";
        for (int j = 0; j < graph2[i].size(); j++) {
            cout << graph2[i][j] + 1 << " ";
        }
    }
    cout << "\n------------\n";
    */

    /*
    int x, y;
    for (int i = 0; i < prevs.size(); i++) {
        for (int j = 0; j < prevs[i].size(); j++) {
            x = prevs[i][j];
            y = i;
            graph2[x].push_back(y);
            graph2[y].push_back(x);
            //cout << x << " " << y << "\n";
            m[x] = true;    // ???????? Segmentation fault
            m[y] = true;
            //cout << n << " " << x << " " << y << "\n";
        }
    }
    */
    /*
    for (int i = 0; i < graph2.size(); i++) {
        cout << "\n" << i + 1 << "   ";
        for (int j = 0; j < graph2[i].size(); j++) {
            cout << graph2[i][j] + 1 << " ";
        }
    }
    cout << "\n";
    */

    //cout << "\n-----------------\n";
    // determine which of the edges from graph2 are bridges
    // take every edge and find if it affects the connectivity or not
    // if it affectes the connectivity, then it
    vector<bool> edge_examined(num_edges, false);
    bool is_connected = true;
    int count = 0;
    int t;
    for (int i = 0; i < graph2.size(); i++) {
        for (int j = 0; j < graph2[i].size(); j++) {
            //cout << i + 1 << " " << graph2[i][j] + 1 << "\n";
            if (m_roads.find(make_pair(make_pair(graph2[i][j] + 1, i + 1),
                                       m_costs[make_pair(graph2[i][j] + 1, i + 1)])) != m_roads.end() &&
                edge_examined[m_roads[make_pair(make_pair(graph2[i][j] + 1, i + 1),
                                                m_costs[make_pair(graph2[i][j] + 1, i + 1)])]]) {
                //cout << i + 1 << " " << graph2[i][j] + 1 << "\n";
                continue;   // this if is, maybe, pointless
            }
            //cout << i + 1 << " " << graph2[i][j] + 1 << "\n";

            //cout << "\n";
            //cout << i+1 << " " << graph2[i][j]+1 << " " << m_edges_in_graph2[make_pair(i+1, graph2[i][j]+1)];
            if (m_edges_in_graph2[make_pair(i + 1, graph2[i][j] + 1)] > 1) {
                continue;
            }
            if (m_edges_in_graph2.find(make_pair(graph2[i][j] + 1, i + 1)) != m_edges_in_graph2.end()) {
                continue;
            }
            is_connected = true;
            count = 0;
            //t = graph2[i][j];
            //graph2[i][j] = -1;

            fill(visited2.begin(), visited2.end(), false);
            //cout << i + 1 << " " << t + 1 << "\n";
            bfs(source, i, graph2[i][j]);
            for (auto it = m.begin(); it != m.end() && is_connected; it++) {
                //cout << it->first + 1 << "aaaaaaa\n";
                if (!visited2[it->first]) {
                	is_connected = false;
                }
            }
            //cout << "\n" << i+1 <<" "<< graph2[i][j]+1 << " is_connected = " << is_connected << "\n";
            if (!is_connected) { // we've found a bridge edge
                x = i;
                y = graph2[i][j];
                //cout << x + 1 << " " << y + 1 << "\n";
                //cout << "aaaaaa " << m_roads[make_pair(x + 1, y + 1)] << "\n";
                if (m_roads.find(make_pair(make_pair(x + 1, y + 1),
                                           m_costs[make_pair(x + 1, y + 1)])) != m_roads.end()) {
                    //cout << m_roads[make_pair(x + 1, y + 1)] << "\n";
                    roads_final[m_roads[make_pair(make_pair(x + 1, y + 1),
                                                  m_costs[make_pair(x + 1, y + 1)])]] = make_pair("YES", 0);
                    //cout << "bridge " << x + 1 << " " << y + 1 << "\n";
                    //cout << " " << m_costs[make_pair(x + 1, y + 1)] << "\n";  // printing bridge edges
                }
                if (m_roads.find(make_pair(make_pair(y + 1, x + 1),
                                           m_costs[make_pair(y + 1, x + 1)])) != m_roads.end()) {
                    //cout << m_roads[make_pair(x + 1, y + 1)] << "\n";
                    roads_final[m_roads[make_pair(make_pair(y + 1, x + 1),
                                                  m_costs[make_pair(y + 1, x + 1)])]] = make_pair("YES", 0);
                    //cout << "bridge " << y + 1 << " " << x + 1 << "\n";
                    //cout << " " << m_costs[make_pair(x + 1, y + 1)] << "\n";  // printing bridge edges
                }
                //edge_examined[m_roads[make_pair(x + 1, y + 1)]] = true;
            }

            edge_examined[m_roads[make_pair(make_pair(i + 1, graph2[i][j] + 1),
                                            m_costs[make_pair(i + 1, graph2[i][j] + 1)])]] = true;
            //graph2[i][j] = t;
        }

    }
    // until now we've determined the edges that will be marked with "YES"
    distance_source_destination = distance[destination];

    for (int i = 0; i < roads_final.size(); i++) {
        if (roads_final[i].second == -1) { // it is a candidate edge to be marked either with "NO" or "CAN x"
            roads_final[i] = repairOrNotEdge(i, distance);
        }
    }

    for (auto it = roads_final.begin(); it != roads_final.end(); it++) {
        cout << it->first;
        if (it->first == "CAN") {
            cout << " " << it->second;
        }
        cout << "\n";
    }
}

int main() {
    int n, num_edges;
    int source, destination;
#ifndef ONLINE_JUDGE
    freopen("president_and_roads.in", "r", stdin);
#endif /* ONLINE_JUDGE */

    cin >> n >> num_edges;
    cin >> source >> destination;

    source--;
    destination--;

    source_initial = source;
    destination_initial = destination;

    graph.resize(n);
    visited.resize(n, false);

    int prev_x = -1, prev_y = -1, prev_cost = -1;
    bool same_edge = true;
    int x, y, cost;
    for (int i = 0; i < num_edges; i++) {
        cin >> x >> y >> cost;
        x--;
        y--;
        graph[x].push_back(make_pair(y, cost)); // oriented graph

        edges.push_back(make_pair(make_pair(x, y), cost));
        //m_roads[make_pair(x, y)] = i;
        m_roads.insert(make_pair(make_pair(make_pair(x + 1, y + 1),
                                           cost),
                                 i));
        m_costs.insert(make_pair(make_pair(x + 1, y + 1), cost));

        if (same_edge && i > 0) {
            if (!(x == prev_x && y == prev_y && cost == prev_cost)) {
                same_edge = false;
            }
        }
        prev_x = x;
        prev_y = y;
        prev_cost = cost;
    }

    if (same_edge && num_edges > 1) {
        for (int i = 0; i < num_edges; i++) {
            cout << "CAN 1\n";
        }
        return 0;
    }

    /*
    for (int i = 0; i < n; i++) {
        cout << "\n" << i+1 << " - ";
        for (int j = 0; j < graph[i].size(); j++) {
            cout << "(" << graph[i][j].first+1 << " " << graph[i][j].second << ") ";
        }
    }
    */

    solve(n, num_edges, source, destination);

    return 0;
}