Problem:
Stamp Rally
スタンプラリー
日本アミューズメントグループ (Japan Amusement Group, JAG) では，島国を模したテーマパークでのイベントを企画している．
このイベントでは，参加者は橋を渡るたびに橋ごとに決められたスタンプをスタンプ帳に順番に押していく．
用意されたスタンプは以下の7種類のどれかである．
a ( ) [ ] + *
スタートからゴールまで橋を渡り歩いて，押されたスタンプの列が正しい数式になればクリアである．
ただし橋を渡る向きは決まっていて，逆向きに渡ることはできない．
同じ橋を何度も渡ってよく，最終的にゴール地点に到着するのであれば一度ゴール地点に着いた後に引き続きスタンプを集めてもよい．
正しい数式とは以下の BNF で定義される <expression> である．
<expression> ::= <term> | <expression> "+" <term>
<term>       ::= <factor> | <term> "*" <factor>
<factor>     ::= "a" | "(" <expression> ")" | "[" <expression> "]"
スタート・ゴールと橋ごとのスタンプを決めたので，関係者で試しにやってみたがなかなかクリアする人が現れない．
もしかしたら，この設定ではクリアすることができないのかもしれない．
スタート・ゴールと橋の情報が与えられるので，クリア可能かどうかを判定するプログラムを書きなさい．
Input
入力は50個以下のデータセットからなる．各データセットは以下の形式で表される．
n
m
s
t
a
1
b
1
c
1
...
a
m
b
m
c
m
データセットの最初の行は，空白文字1個で区切られた4個の整数
n
,
m
,
s
,
t
からなる．
n
は島の数であり， 1 ≤
n
≤ 200 と仮定してよい．
それぞれの島には 1 から
n
までの番号が付けられている．
m
は橋の数であり， 1 ≤
m
≤ 100,000 と仮定してよい．
s
はスタートの島の番号，
t
はゴールの島の番号である．スタートとゴールが同じ島であることもある．
続く
m
行のそれぞれは，空白文字1個で区切られた2個の整数と1個の文字からなる．
a
i
，
b
i
は
i
番目の橋によって島
a
i
から島
b
i
へ渡れることを表し，
c
i
は
i
番目の橋で押すスタンプを表す．ある2つの島の間に複数の橋がかかっていたり，1つの島の中で橋がかかっていたりすることもある．
入力の終わりは，4つのゼロからなる1行で示される．
Output
各データセットに対して，クリアできるならば"
Yes
"を，できないならば"
No
"を1行に出力せよ．
Sample Input
4 5 1 4
1 2 (
1 3 a
2 4 a
3 4 )
3 2 +
4 4 1 2
1 3 (
3 4 a
4 1 +
3 2 a
3 4 1 1
1 2 a
2 2 +
2 3 a
3 1 a
5 8 1 5
1 1 [
1 2 (
2 1 *
2 2 a
2 3 a
3 3 )
3 4 ]
4 5 )
2 14 1 1
1 2 a
1 2 (
1 2 )
1 2 [
1 2 ]
1 2 +
1 2 *
2 1 a
2 1 (
2 1 )
2 1 [
2 1 ]
2 1 +
2 1 *
0 0 0 0
Output for Sample Input
Yes
No
No
Yes
No

Submitted solutions:

code_snippet: #include <bits/stdc++.h>
using namespace std;
const int N = 205;
int id(char c) {
	if (c == 'a') return 0;
	if (c == '+') return 1;
	if (c == '*') return 2;
	if (c == '(') return 3;
	if (c == ')') return 4;
	if (c == '[') return 5;
	return 6;
}
//vector<int> G[N][7];
bool vis[N][N][5], can[N][N][5], bridge[N][N][7];
int n;
bool dfs(int s, int t, int type) {
	bool &ans = can[s][t][type], &flag = vis[s][t][type];
	//printf("%d %d %d\n", s, t, type);
	if (flag) return ans;
	flag = 1;
	ans = 0;
	if (type == 0) {
		for (int i = 1; i <= n && !ans; ++ i) if (bridge[s][i][3]) ans |= dfs(i, t, 3);
		for (int i = 1; i <= n && !ans; ++ i) if (bridge[s][i][5]) ans |= dfs(i, t, 4);
		for (int i = 1; i <= n && !ans; ++ i) if (dfs(s, i, 0)) ans |= dfs(i, t, 1) || dfs(i, t, 2);
	}
	else if (type == 1) {
		for (int i = 1; i <= n && !ans; ++ i) if (bridge[s][i][1]) ans |= dfs(i, t, 0);
	}
	else if (type == 2) {
		for (int i = 1; i <= n && !ans; ++ i) if (bridge[s][i][2]) ans |= dfs(i, t, 0);
	}
	else if (type == 3) {
		for (int i = 1; i <= n && !ans; ++ i) if (bridge[i][t][4]) ans |= dfs(s, i, 0);
	}
	else if (type == 4) {
		for (int i = 1; i <= n && !ans; ++ i) if (bridge[i][t][6]) ans |= dfs(s, i, 0);
	}
	return ans;
}
int main() {
	while (true) {
		int m, s, t;
		scanf("%d%d%d%d", &n, &m, &s, &t);
		if (n + m + s + t == 0) break;
		//for (int i = 1; i <= n; ++ i) G[i].clear();
		memset(vis, 0, sizeof(vis));
		memset(bridge, 0, sizeof(bridge));
		for (int i = 0; i < m; ++ i) {
			static char s[5];
			static int u, v;
			scanf("%d%d%s", &u, &v, s);
			bridge[u][v][id(s[0])] = 1;
			//G[id(s[0])][u].push_back(v);
			if (s[0] == 'a') {
				vis[u][v][0] = 1;
				can[u][v][0] = 1;
			}
		}
		//int t1, t2, t3;
		//t1 = 2, t2 = 2, t3 = 0;
		//printf("%d %d %d : %s\n", t1, t2, t3, dfs(t1, t2, t3) ? "Yes" : "No");
		puts(dfs(s, t, 0) ? "Yes" : "No");
	}
}
accuracy: 1
time_ms: 170
memory_kb: 5460
final_rank: 1

code_snippet: // #ifndef ONLINE_JUDGE
// #define _GLIBCXX_DEBUG
// #endif
#pragma GCC optimize("O3")
#pragma GCC optimize("unroll-loops")
#include <bits/stdc++.h>
using namespace std;
#include <atcoder/all>
using namespace atcoder;
// #include <boost/rational.hpp>
// using namespace boost;
// using rat = rational<long long int>;
using mint = modint998244353;
// using mint = modint1000000007;
// using mint = mint;
using ll = long long;
using ld = long double;
using ull = uint64_t;
using pll = pair<ll, ll>;
using vll = vector<ll>;
using vvll = vector<vll>;
using vvvll = vector<vvll>;
using vpll = vector<pll>;
using vvpll = vector<vpll>;
using vm = vector<mint>;
using vvm = vector<vm>;
using vvvm = vector<vvm>;
using vstr = vector<string>;
#define v(T) vector<T>
#define vv(T) vector<vector<T>>
#define vvv(T) vector<vector<vector<T>>>
#define vvvv(T) vector<vector<vector<vector<T>>>>

istream &operator>>(istream &is, mint &a){ll tmp; is >> tmp; a = tmp; return is;}
ostream &operator<<(ostream &os, const mint &a){ os << a.val(); return os; }
string to_string(const __int128_t &a) { if (a == 0) return "0"; string s = ""; __int128_t num = a; bool is_negative = false; if (num < 0) { is_negative = true; num = -num; } while (num > 0) { s += '0' + (num % 10); num /= 10; } if (is_negative) s += '-'; reverse(s.begin(), s.end()); return s; }
istream &operator>>(istream &is, __int128_t &a){ string s; is >> s; a = 0; for(char c : s) { if(isdigit(c)) {a = a*10 + (c - '0'); }  } if(s[0]=='-'){ a *= -1; } return is; }
ostream &operator<<(ostream &os, const __int128_t &a){ os << to_string(a); return os; }
template<class T, class U> istream &operator>>(istream &is, pair<T, U> &p) { is >> p.first >> p.second; return is; }
template<class T, class U> ostream &operator<<(ostream &os, const pair<T, U> &p) { os << p.first << " " << p.second; return os; }
template<class T> istream &operator>>(istream &is, vector<T> &vec){ for(T &e : vec){is >> e;} return is; }
template<class T> ostream &operator<<(ostream &os, const vector<T> &vec) { for(int i = 0; i < (int)vec.size(); i++) { os << vec[i] << (i + 1 != (int)vec.size() ? " " : ""); } return os; }

template <class... T> constexpr auto min (T... a) { return min(initializer_list<common_type_t<T...>>{a...}); }
template <class... T> constexpr auto max (T... a) { return max(initializer_list<common_type_t<T...>>{a...}); }
template<class T> using pqg = priority_queue<T, vector<T>, greater<T>>;
template<class T> T opmin(T x, T y) { return min(x, y); }
template<class T> T einf() { return numeric_limits<T>::max(); }
template<class T> T opmax(T x, T y) { return max(x, y); }
template<class T> T eminf() { return numeric_limits<T>::min(); }
template<class T> T opsum(T x, T y) { return x + y; }
template<class T> T ezero() { return (T)0; }
// #define maxseg(T) segtree<T, [](T x, T y){return max(x, y);}, [](){return (T)(-(1LL << 60));}>
// #define minseg(T) segtree<T, [](T x, T y){return min(x, y);}, [](){return (T)((1LL << 60));}>
// #define sumseg(T) segtree<T, [](T x, T y){return x + y;}, [](){return (T)(0);}>
template<class T> using minseg = segtree<T, opmin<T>, einf<T>>;
template<class T> using maxseg = segtree<T, opmax<T>, eminf<T>>;
template<class T> using sumseg = segtree<T, opsum<T>, ezero<T>>;
// template<class T> struct v : vector<T> { using vector<T> :: vector; };
// template<class T> struct vv : vector<v<T>> { using vector<v<T>> :: vector; };
// template<class T> struct vvv : vector<vv<T>> { using vector<vv<T>> :: vector; };
template<class T> inline bool chmin(T& a, T b) {if(a > b){a = b; return true;} else {return false;}};
template<class T> inline bool chmax(T& a, T b) {if(a < b){a = b; return true;} else {return false;}};
#define rep(i,n) for(ll i = 0; i < (ll)(n); i++)
#define repr(i,n) for(ll i = (ll)(n) - 1; i >= 0; i--)
#define REP(i, l, r) for(ll i = (ll)l; i <= (ll)(r); i++)
#define REPR(i, l, r) for(ll i = (ll)r; i >= (ll)(l); i--)
const ll inf = (1 << 30);
const ll INF = (1LL << 60);
const vector<pair<ll, ll>> DIJ = {{1, 0}, {0, -1}, {-1, 0}, {0, 1}};
void out(){cout<<'\n';}
template<class T, class... Ts> void out(const T& a, const Ts&... b){ cout<<a; (cout<<... << (cout << ' ', b)); cout << '\n';}
void outf(){cout<<endl;}
template<class T, class... Ts> void outf(const T& a, const Ts&... b){ cout<<a; (cout<<... << (cout << ' ', b)); cout << endl;}
template<class T, class U> void outp(pair<T, U> a){ out((a).first, (a).second); }
template<class T, class U> void outpf(pair<T, U> a){ outf((a).first, (a).second); }
template<class T> void outv(T a){rep(i, (a).size()){ cout << (a)[i] << " "; } cout << endl;}
template<class T> void outvL(T a){rep(i, (a).size()){out((a)[i]);} cout << flush; }
// template<class T> void outvv(T a){rep(i, a.size()){ rep(j, a.at(i).size()){cout << a.at(i).at(j) << " "; } cout << endl; }}
// template<class T> void outvp(T a){rep(i, a.size()){ out2(a.at(i).first, a.at(i).second); }}
void setpre(int a){cout << fixed << setprecision(a);}
#define outN out("No")
#define outY out("Yes")
#define outYN(flag) out(flag ? "Yes" : "No")
#define dame(...) {outf(__VA_ARGS__);return 0;}

template<class T> void read(vector<T>& vec){ for(int i = 0; i < (int)vec.size(); i++) { cin >> vec[i]; } }
template<class... T> void read(T&... a){(cin >> ... >> a);}
#define readll(...) ll __VA_ARGS__; read(__VA_ARGS__)
#define readvll(a, n) vector<ll> a(n); read(a)
#define readvt(type, a, n) vector<type> a(n); read(a)
#define readvll2(a, b, n) vector<ll> a(n), b(n); for(int lopi = 0; lopi < (int)(n); lopi++) cin >> (a)[lopi] >> (b)[lopi]
#define readvll3(a, b, c, n) vector<ll> a(n), b(n), c(n); for(int lopi = 0; lopi < (int)(n); lopi++) cin >> (a)[lopi] >> (b)[lopi] >> (c)[lopi]
#define readstr(...) string __VA_ARGS__; read(__VA_ARGS__)
#define readundirG(G, N, M) G = vvll(N); rep(lopi, M) {ll a, b; cin >> a >> b; G[a-1].push_back(b-1); G[b-1].push_back(a-1);}
#define readdirG(G, N, M) G = vvll(N); rep(lopi, M) {ll a, b; cin >> a >> b; G[a-1].push_back(b-1);}
#define readundirwghG(G, N, M) G = vv(pll)(N); rep(lopi, M) {ll a, b, c; cin >> a >> b >> c; G[a-1].emplace_back(b-1,c); G[b-1].emplace_back(a-1, c);}
#define readdirwghG (G, N, M) G = vv(pll)(N); rep(lopi, M) {ll a, b, c; cin >> a >> b >> c; G[a-1].emplace_back(b-1, c);}

#define All(a) (a).begin(), (a).end()
template<class T> inline void sortr(T& a){ sort((a).rbegin(), (a).rend()); }
template<class T> inline vector<int> argsort(T V, bool rev = false){vector<int> res(V.size()); iota(res.begin(), res.end(), 0); sort(res.begin(), res.end(), [&](int x, int y){if(!rev){return V[x] < V[y];}else{return V[x] > V[y];}}); return res;}
template<class T, class U> inline void sort_by_idx(T& V, vector<U>& I){assert(V.size() == I.size()); T tmpv = V; for(int loopi = 0; loopi < (int)I.size(); loopi++){V[loopi] = tmpv[I.at(loopi)];}}
template<class T, class U> inline void sortp(vector<T>& v1, vector<U>& v2, bool rev1 = false, int rev2 = false){assert(v1.size() == v2.size()); vector<int> I(v1.size()); iota(I.begin(), I.end(), 0); sort(I.begin(), I.end(), [&](const int x, const int y){if(v1[x] != v1[y]){return (bool)(rev1 ^ (v1[x] < v1[y]));}else{if(v2[x]==v2[y]){return false;} return (bool)(rev2 ^ (v2[x] < v2[y]));}}); sort_by_idx(v1, I); sort_by_idx(v2, I);}
template<class T> T POW(T x, ll n) {T ret = 1; while(n > 0){if(n & 1) ret *= x; x *= x; n >>= 1;} return ret;}
ll powll(ll x, ll n){ll ret = 1; while(n > 0){if(n & 1) ret *= x; x *= x; n >>= 1;} return ret;}
inline ll divceil(ll x, ll y) { if(x >= 0) {return(x / y + (ll)(x % y != 0)); } else { return -((-x) / y); } }
inline ll divfloor(ll x, ll y) { if(x >= 0) { return x/y; } else { return -((-x)/y + (ll)((-x) % y != 0)); } }
inline bool inLR(ll x, ll L, ll R){ return (L <= x && x < R); }
inline bool inRect(ll pos_x, ll pos_y, ll rect_H, ll rect_W, ll rect_h = 0, ll rect_w = 0){ return (rect_h <= pos_x && pos_x < rect_H && rect_w <= pos_y && pos_y < rect_W); }

template<class T> vector<T> &operator++(vector<T> &v) {for(auto &e : v){e++;} return v;}
template<class T> vector<T> operator++(vector<T> &v, signed) {auto res=v; for(auto &e : v){e++;} return res;}
template<class T> vector<T> &operator--(vector<T> &v) {for(auto &e : v){e--;} return v;}
template<class T> vector<T> operator--(vector<T> &v, signed) {auto res=v; for(auto &e : v){e--;} return res;}
template<class T> vector<T> operator+(const vector<T> &x, const vector<T> &y) { assert(x.size() == y.size()); vector<T> ret(x.size()); for(int i = 0; i < (int)x.size(); i++) {ret[i] = x[i] + y[i];} return ret; }
template<class T> vector<T> operator-(const vector<T> &x, const vector<T> &y) { assert(x.size() == y.size()); vector<T> ret(x.size()); for(int i = 0; i < (int)x.size(); i++) {ret[i] = x[i] - y[i];} return ret; } 

template<class T, class U> pair<T, U> operator+(const pair<T, U> &x, const pair<T, U> &y) { return make_pair(x.first + y.first, x.second + y.second); }
template<class T, class U> pair<T, U> operator-(const pair<T, U> &x, const pair<T, U> &y) { return make_pair(x.first - y.first, x.second - y.second); }
template<class T, class U> void operator+=(pair<T, U> &x, pair<T, U> &y) { x = x + y; }
template<class T, class U> void operator-=(pair<T, U> &x, pair<T, U> &y) { x = x - y; }

template<class T> size_t HashCombine(const size_t seed,const T &v){ return seed^(std::hash<T>()(v)+0x9e3779b9+(seed<<6)+(seed>>2)); }
template<class T,class S> struct std::hash<std::pair<T,S>>{ size_t operator()(const std::pair<T,S> &keyval) const noexcept { return HashCombine(std::hash<T>()(keyval.first), keyval.second); } };
template<class T> struct std::hash<std::vector<T>>{ size_t operator()(const std::vector<T> &keyval) const noexcept { size_t s=0; for (auto&& v: keyval) s=HashCombine(s,v); return s; } };
template<int N> struct HashTupleCore{ template<class Tuple> size_t operator()(const Tuple &keyval) const noexcept{ size_t s=HashTupleCore<N-1>()(keyval); return HashCombine(s,std::get<N-1>(keyval)); } };
template <> struct HashTupleCore<0>{ template<class Tuple> size_t operator()(const Tuple &keyval) const noexcept{ return 0; } };
template<class... Args> struct std::hash<std::tuple<Args...>>{ size_t operator()(const tuple<Args...> &keyval) const noexcept { return HashTupleCore<tuple_size<tuple<Args...>>::value>()(keyval); } };

int main()
{
    std::cin.tie(nullptr), std::ios_base::sync_with_stdio(false);
    while(true)
    {
        readll(N, M, s, t);
        if(!N) break;
        s--; t--;
        vv(bool) dpe(N, v(bool)(N, 0)), dpt(N, v(bool)(N, 0)), dpf(N, v(bool)(N, 0));
        vvvll G(N, vvll(7)), rG(N, vvll(7));
        // unordered_map<char, int> mp = {{'a', 0}, {'(', 1}, {')', 2}, {'[', 3}, {']', 4}, {'+', 5}, {'*', 6}};
        queue<pll> qe, qt, qf;
        vvll Dt(N), De(N), rDt(N), rDe(N);
        rep(i, M)
        {
            readll(a, b);
            char c; read(c);
            a--; b--;
            ll id = c == 'a' ? 0 : (c == '(' ? 1 : (c == ')' ? 2 : (c == '[' ? 3 : (c == ']' ? 4 : (c == '+' ? 5 : 6)))));
            G[a][id].emplace_back(b);
            rG[b][id].emplace_back(a);
            if(id == 0 && !dpf[a][b])
            {
                dpf[a][b] = true;
                qf.emplace(a, b);
            }
        }
        rep(i, N)
        {
            rep(j, 7)
            {
                sort(All(G[i][j]));
                G[i][j].erase(unique(All(G[i][j])), G[i][j].end());
            }
        }
        while(!qf.empty() && !dpe[s][t])
        {
            while(!qf.empty())
            {
                auto [a, b] = qf.front(); qf.pop();
                // out(1, a, b);
                if(!dpt[a][b])
                {
                    dpt[a][b] = true;
                    qt.emplace(a, b);
                    Dt[a].emplace_back(b);
                    rDt[b].emplace_back(a);
                }
                for(auto c : rG[a][6])
                {
                    for(auto d : rDt[c])
                    {
                        if(dpt[d][b]) continue;
                        if(dpt[d][c])
                        {
                            dpt[d][b] = true;
                            qt.emplace(d, b);
                            Dt[d].emplace_back(b);
                            rDt[b].emplace_back(d);
                        }
                    }
                }
                for(auto c : G[b][6])
                {
                    for(auto d : Dt[c])
                    {
                        if(dpt[a][d]) continue;
                        if(dpt[c][d])
                        {
                            dpt[a][d] = true;
                            qt.emplace(a, d);
                            Dt[a].emplace_back(d);
                            rDt[d].emplace_back(a);
                        }
                    }
                }
            }
            while(!qt.empty() && !dpe[s][t])
            {
                auto [a, b] = qt.front(); qt.pop();
                // out(2, a, b);
                if(!dpe[a][b])
                {
                    dpe[a][b] = true;
                    qe.emplace(a, b);
                    De[a].emplace_back(b);
                    rDe[b].emplace_back(a);
                }
                for(auto c : rG[a][6])
                {
                    for(auto d : rDt[c])
                    {
                        if(dpt[d][b]) continue;
                        if(dpt[d][c])
                        {
                            dpt[d][b] = true;
                            qt.emplace(d, b);
                            Dt[d].emplace_back(b);
                            rDt[b].emplace_back(d);
                        }
                    }
                }
                for(auto c : G[b][6])
                {
                    for(auto d : Dt[c])
                    {
                        if(dpt[a][d]) continue;
                        if(dpt[c][d])
                        {
                            dpt[a][d] = true;
                            qt.emplace(a, d);
                            Dt[a].emplace_back(d);
                            rDt[d].emplace_back(a);
                        }
                    }
                }
                for(auto c : rG[a][5])
                {
                    for(auto d : rDe[c])
                    {
                        if(dpe[d][b]) continue;
                        if(dpe[d][c])
                        {
                            dpe[d][b] = true;
                            qe.emplace(d, b);
                            De[d].emplace_back(b);
                            rDe[b].emplace_back(d);
                        }
                    }
                }
                for(auto c : G[b][5])
                {
                    for(auto d : De[c])
                    {
                        if(dpe[a][d]) continue;
                        if(dpe[c][d])
                        {
                            dpe[a][d] = true;
                            qe.emplace(a, d);
                            De[a].emplace_back(d);
                            rDe[d].emplace_back(a);
                        }
                    }
                }
            }
            while(!qe.empty())
            {
                auto [a, b] = qe.front(); qe.pop();
                // out(3, a, b);
                if(rG[a][1].size() && G[b][2].size())
                {
                   for(auto c : rG[a][1]) for(auto d : G[b][2])
                    {
                        if(!dpf[c][d])
                        {
                            dpf[c][d] = true;
                            qf.emplace(c, d);
                        }
                    } 
                }
                for(auto c : rG[a][5])
                {
                    for(auto d : rDe[c])
                    {
                        if(dpe[d][b]) continue;
                        if(dpe[d][c])
                        {
                            dpe[d][b] = true;
                            qe.emplace(d, b);
                            De[d].emplace_back(b);
                            rDe[b].emplace_back(d);
                        }
                    }
                }
                for(auto c : G[b][5])
                {
                    for(auto d : De[c])
                    {
                        if(dpe[a][d]) continue;
                        if(dpe[c][d])
                        {
                            dpe[a][d] = true;
                            qe.emplace(a, d);
                            De[a].emplace_back(d);
                            rDe[d].emplace_back(a);
                        }
                    }
                }
                if(rG[a][3].size() && G[b][4].size())
                {
                  for(auto c : rG[a][3]) for(auto d : G[b][4])
                    {
                        if(!dpf[c][d])
                        {
                            dpf[c][d] = true;
                            qf.emplace(c, d);
                        }
                    }  
                }
            }
        }
        outYN(dpe[s][t]);
        // outvL(dpe);
        // out();
        // outvL(dpt);
        // out();
        // outvL(dpf);
        // cout << flush;
    }
}
accuracy: 1
time_ms: 6200
memory_kb: 9004
final_rank: 19

code_snippet: // AOJ #2704 Stamp Rally
// 2025.3.2

#include <bits/stdc++.h>
using namespace std;

const int NTN = 13;

struct TerminalRule {
    int A;
    char terminal;
};
const vector<TerminalRule> terminalRules = {
    {2, 'a'},
    {3, '('},
    {4, ')'},
    {5, '['},
    {6, ']'},
    {11, '+'},
    {12, '*'}
};

struct UnitRule { int A, B; };
const vector<UnitRule> unitRules = {
    {0, 1},
    {1, 2}
};

struct BinaryRule { int A, B, C; };
const vector<BinaryRule> binaryRules = {
    {0, 0, 9},
    {1, 1, 10},
    {2, 3, 7},
    {7, 0, 4},
    {2, 5, 8},
    {8, 0, 6},
    {9, 11, 1},
    {10, 12, 2}
};

struct Edge {
    int u, v;
    char label;
};

int main(){
    ios::sync_with_stdio(0);
    cin.tie(0);

    while(true){
        int n, m, s, t;
        cin >> n >> m >> s >> t;
        if(n==0) break;
        s--; t--;

        vector<Edge> edges(m);
        for (int i = 0; i < m; i++){
            int u, v;
            char c;
            cin >> u >> v >> c;
            edges[i] = {u-1, v-1, c};
        }

        vector<vector<vector<bool>>> dp(NTN, vector<vector<bool>>(n, vector<bool>(n, false)));
        queue<tuple<int,int,int>> Q;

        auto add = [&](int A, int i, int j) -> void {
            if(!dp[A][i][j]){
                dp[A][i][j] = true;
                Q.push({A, i, j});
            }
        };

        for (auto &e : edges) {
            for (auto &tr : terminalRules) {
                if(e.label == tr.terminal){
                    add(tr.A, e.u, e.v);
                }
            }
        }

        while(!Q.empty()){
            auto [X, i, j] = Q.front();
            Q.pop();
            for (auto &ur : unitRules) {
                if(ur.B == X) add(ur.A, i, j);
            }
            for (auto &br : binaryRules) {
                if(br.B == X){
                    for (int k = 0; k < n; k++){
                        if(dp[br.C][j][k]) add(br.A, i, k);
                    }
                }
            }
            for (auto &br : binaryRules) {
                if(br.C == X){
                    for (int k = 0; k < n; k++){
                        if(dp[br.B][k][i]) add(br.A, k, j);
                    }
                }
            }
        }
        cout << (dp[0][s][t] ? "Yes" : "No") << endl;
    }
    return 0;
}
accuracy: 1
time_ms: 540
memory_kb: 6316
final_rank: 8

code_snippet: #include <bits/stdc++.h>

using namespace std;

#define rep(i, a, b) for (int i = (int)(a); i < (int)(b); i++)
#define rrep(i, a, b) for (int i = (int)(b)-1; i >= (int)(a); i--)
#define ALL(v) (v).begin(), (v).end()
#define UNIQUE(v) sort(ALL(v)), (v).erase(unique(ALL(v)), (v).end())
#define SZ(v) (int)v.size()
#define MIN(v) *min_element(ALL(v))
#define MAX(v) *max_element(ALL(v))
#define LB(v, x) int(lower_bound(ALL(v), (x)) - (v).begin())
#define UB(v, x) int(upper_bound(ALL(v), (x)) - (v).begin())

using uint = unsigned int;
using ll = long long int;
using ull = unsigned long long;
using i128 = __int128_t;
using u128 = __uint128_t;
const int inf = 0x3fffffff;
const ll INF = 0x1fffffffffffffff;

template <typename T> inline bool chmax(T &a, T b) {
    if (a < b) {
        a = b;
        return 1;
    }
    return 0;
}
template <typename T> inline bool chmin(T &a, T b) {
    if (a > b) {
        a = b;
        return 1;
    }
    return 0;
}
template <typename T, typename U> T ceil(T x, U y) {
    assert(y != 0);
    if (y < 0)
        x = -x, y = -y;
    return (x > 0 ? (x + y - 1) / y : x / y);
}
template <typename T, typename U> T floor(T x, U y) {
    assert(y != 0);
    if (y < 0)
        x = -x, y = -y;
    return (x > 0 ? x / y : (x - y + 1) / y);
}
template <typename T> int popcnt(T x) {
    return __builtin_popcountll(x);
}
template <typename T> int topbit(T x) {
    return (x == 0 ? -1 : 63 - __builtin_clzll(x));
}
template <typename T> int lowbit(T x) {
    return (x == 0 ? -1 : __builtin_ctzll(x));
}

template <class T, class U>
ostream &operator<<(ostream &os, const pair<T, U> &p) {
    os << "P(" << p.first << ", " << p.second << ")";
    return os;
}
template <typename T> ostream &operator<<(ostream &os, const vector<T> &vec) {
    os << "{";
    for (int i = 0; i < vec.size(); i++) {
        os << vec[i] << (i + 1 == vec.size() ? "" : ", ");
    }
    os << "}";
    return os;
}
template <typename T, typename U>
ostream &operator<<(ostream &os, const map<T, U> &map_var) {
    os << "{";
    for (auto itr = map_var.begin(); itr != map_var.end(); itr++) {
        os << "(" << itr->first << ", " << itr->second << ")";
        itr++;
        if (itr != map_var.end())
            os << ", ";
        itr--;
    }
    os << "}";
    return os;
}
template <typename T> ostream &operator<<(ostream &os, const set<T> &set_var) {
    os << "{";
    for (auto itr = set_var.begin(); itr != set_var.end(); itr++) {
        os << *itr;
        ++itr;
        if (itr != set_var.end())
            os << ", ";
        itr--;
    }
    os << "}";
    return os;
}
#ifdef LOCAL
#define show(...) _show(0, #__VA_ARGS__, __VA_ARGS__)
#else
#define show(...) true
#endif
template <typename T> void _show(int i, T name) {
    cerr << '\n';
}
template <typename T1, typename T2, typename... T3>
void _show(int i, const T1 &a, const T2 &b, const T3 &...c) {
    for (; a[i] != ',' && a[i] != '\0'; i++)
        cerr << a[i];
    cerr << ":" << b << " ";
    _show(i + 1, a, c...);
}

#include <unistd.h>

namespace fastio {
static constexpr uint32_t SZ = 1 << 17;
char ibuf[SZ];
char obuf[SZ];
char out[100];
// pointer of ibuf, obuf


uint32_t pil = 0, pir = 0, por = 0;

struct Pre {
    char num[10000][4];
    constexpr Pre() : num() {
        for (int i = 0; i < 10000; i++) {
            int n = i;
            for (int j = 3; j >= 0; j--) {
                num[i][j] = n % 10 | '0';
                n /= 10;
            }
        }
    }
} constexpr pre;

inline void load() {
    memmove(ibuf, ibuf + pil, pir - pil);
    pir = pir - pil + fread(ibuf + pir - pil, 1, SZ - pir + pil, stdin);
    pil = 0;
    if (pir < SZ)
        ibuf[pir++] = '\n';
}

inline void flush() {
    fwrite(obuf, 1, por, stdout);
    por = 0;
}

void rd(char &c) {
    do {
        if (pil + 1 > pir)
            load();
        c = ibuf[pil++];
    } while (isspace(c));
}

void rd(string &x) {
    x.clear();
    char c;
    do {
        if (pil + 1 > pir)
            load();
        c = ibuf[pil++];
    } while (isspace(c));
    do {
        x += c;
        if (pil == pir)
            load();
        c = ibuf[pil++];
    } while (!isspace(c));
}

template <typename T> void rd_real(T &x) {
    string s;
    rd(s);
    x = stod(s);
}

template <typename T> void rd_integer(T &x) {
    if (pil + 100 > pir)
        load();
    char c;
    do
        c = ibuf[pil++];
    while (c < '-');
    bool minus = 0;
    if constexpr (is_signed<T>::value || is_same_v<T, i128>) {
        if (c == '-') {
            minus = 1, c = ibuf[pil++];
        }
    }
    x = 0;
    while ('0' <= c) {
        x = x * 10 + (c & 15), c = ibuf[pil++];
    }
    if constexpr (is_signed<T>::value || is_same_v<T, i128>) {
        if (minus)
            x = -x;
    }
}

void rd(int &x) {
    rd_integer(x);
}
void rd(ll &x) {
    rd_integer(x);
}
void rd(i128 &x) {
    rd_integer(x);
}
void rd(uint &x) {
    rd_integer(x);
}
void rd(ull &x) {
    rd_integer(x);
}
void rd(u128 &x) {
    rd_integer(x);
}
void rd(double &x) {
    rd_real(x);
}
void rd(long double &x) {
    rd_real(x);
}

template <class T, class U> void rd(pair<T, U> &p) {
    return rd(p.first), rd(p.second);
}
template <size_t N = 0, typename T> void rd_tuple(T &t) {
    if constexpr (N < std::tuple_size<T>::value) {
        auto &x = std::get<N>(t);
        rd(x);
        rd_tuple<N + 1>(t);
    }
}
template <class... T> void rd(tuple<T...> &tpl) {
    rd_tuple(tpl);
}

template <size_t N = 0, typename T> void rd(array<T, N> &x) {
    for (auto &d : x)
        rd(d);
}
template <class T> void rd(vector<T> &x) {
    for (auto &d : x)
        rd(d);
}

void read() {}
template <class H, class... T> void read(H &h, T &...t) {
    rd(h), read(t...);
}

void wt(const char c) {
    if (por == SZ)
        flush();
    obuf[por++] = c;
}
void wt(const string s) {
    for (char c : s)
        wt(c);
}
void wt(const char *s) {
    size_t len = strlen(s);
    for (size_t i = 0; i < len; i++)
        wt(s[i]);
}

template <typename T> void wt_integer(T x) {
    if (por > SZ - 100)
        flush();
    if (x < 0) {
        obuf[por++] = '-', x = -x;
    }
    int outi;
    for (outi = 96; x >= 10000; outi -= 4) {
        memcpy(out + outi, pre.num[x % 10000], 4);
        x /= 10000;
    }
    if (x >= 1000) {
        memcpy(obuf + por, pre.num[x], 4);
        por += 4;
    } else if (x >= 100) {
        memcpy(obuf + por, pre.num[x] + 1, 3);
        por += 3;
    } else if (x >= 10) {
        int q = (x * 103) >> 10;
        obuf[por] = q | '0';
        obuf[por + 1] = (x - q * 10) | '0';
        por += 2;
    } else
        obuf[por++] = x | '0';
    memcpy(obuf + por, out + outi + 4, 96 - outi);
    por += 96 - outi;
}

template <typename T> void wt_real(T x) {
    ostringstream oss;
    oss << fixed << setprecision(15) << double(x);
    string s = oss.str();
    wt(s);
}

void wt(int x) {
    wt_integer(x);
}
void wt(ll x) {
    wt_integer(x);
}
void wt(i128 x) {
    wt_integer(x);
}
void wt(uint x) {
    wt_integer(x);
}
void wt(ull x) {
    wt_integer(x);
}
void wt(u128 x) {
    wt_integer(x);
}
void wt(double x) {
    wt_real(x);
}
void wt(long double x) {
    wt_real(x);
}

template <class T, class U> void wt(const pair<T, U> val) {
    wt(val.first);
    wt(' ');
    wt(val.second);
}
template <size_t N = 0, typename T> void wt_tuple(const T t) {
    if constexpr (N < std::tuple_size<T>::value) {
        if constexpr (N > 0) {
            wt(' ');
        }
        const auto x = std::get<N>(t);
        wt(x);
        wt_tuple<N + 1>(t);
    }
}
template <class... T> void wt(tuple<T...> tpl) {
    wt_tuple(tpl);
}
template <class T, size_t S> void wt(const array<T, S> val) {
    auto n = val.size();
    for (size_t i = 0; i < n; i++) {
        if (i)
            wt(' ');
        wt(val[i]);
    }
}
template <class T> void wt(const vector<T> val) {
    auto n = val.size();
    for (size_t i = 0; i < n; i++) {
        if (i)
            wt(' ');
        wt(val[i]);
    }
}

void print() {
    wt('\n');
}
template <class Head, class... Tail> void print(Head &&head, Tail &&...tail) {
    wt(head);
    if (sizeof...(Tail))
        wt(' ');
    print(forward<Tail>(tail)...);
}
void __attribute__((destructor)) _d() {
    flush();
}
} // namespace fastio


using fastio::flush;
using fastio::print;
using fastio::read;

inline void first(bool i = true) {
    print(i ? "first" : "second");
}
inline void Alice(bool i = true) {
    print(i ? "Alice" : "Bob");
}
inline void Takahashi(bool i = true) {
    print(i ? "Takahashi" : "Aoki");
}
inline void yes(bool i = true) {
    print(i ? "yes" : "no");
}
inline void Yes(bool i = true) {
    print(i ? "Yes" : "No");
}
inline void No() {
    print("No");
}
inline void YES(bool i = true) {
    print(i ? "YES" : "NO");
}
inline void NO() {
    print("NO");
}
inline void Yay(bool i = true) {
    print(i ? "Yay!" : ":(");
}
inline void Possible(bool i = true) {
    print(i ? "Possible" : "Impossible");
}
inline void POSSIBLE(bool i = true) {
    print(i ? "POSSIBLE" : "IMPOSSIBLE");
}

/**
 * @brief Fast IO
 */

bool DP[200][200][4];

struct Edge {
    int To;
    char C;
};

struct Query {
    int L, R;
    int Type;
};

int main() {
while(1) {
    int N, M, S, T;
    cin >> N >> M >> S >> T;
    if (N == 0) return 0;
    S--, T--;
    rep(i,0,N) {
        rep(j,0,N) {
            rep(k,0,4) DP[i][j][k] = false;
        }
    }
    vector<vector<Edge>> A(N), B(N);
    rep(i,0,M) {
        int a,b;
        char c;
        cin >> a >> b >> c;
        a--, b--;
        A[b].push_back({a,c});
        B[a].push_back({b,c});
    }
    queue<Query> Q;
    rep(i,0,N) {
        for (Edge E : B[i]) {
            if (E.C == 'a') {
                if (!DP[i][E.To][0]) {
                    DP[i][E.To][0] = true;
                    Q.push({i,E.To,0});
                }
            }
        }
    }
    while(!Q.empty()) {
        Query X = Q.front();
        Q.pop();
        int From = X.L, To = X.R, Type = X.Type;
        if (Type == 0) {
            rep(i,0,N) {
                if (DP[To][i][1]) {
                    if (!DP[From][i][0]) {
                        DP[From][i][0] = true;
                        Q.push({From,i,0});
                    }
                }
            }
            for (Edge E : A[From]) {
                if (E.C == '+' || E.C == '*') {
                    if (!DP[E.To][To][1]) {
                        DP[E.To][To][1] = true;
                        Q.push({E.To,To,1});
                    }
                }
            }
            for (Edge E : B[To]) {
                if (E.C == ')') {
                    if (!DP[From][E.To][2]) {
                        DP[From][E.To][2] = true;
                        Q.push({From,E.To,2});
                    }
                }
                if (E.C == ']') {
                    if (!DP[From][E.To][3]) {
                        DP[From][E.To][3] = true;
                        Q.push({From,E.To,3});
                    }
                }
            }
        }
        if (Type == 1) {
            rep(i,0,N) {
                if (DP[i][From][0]) {
                    if (!DP[i][To][0]) {
                        DP[i][To][0] = true;
                        Q.push({i,To,0});
                    }
                }
            }
        }
        if (Type == 2) {
            for (Edge E : A[From]) {
                if (E.C == '(') {
                    if (!DP[E.To][To][0]) {
                        DP[E.To][To][0] = true;
                        Q.push({E.To,To,0});
                    }
                }
            }
        }
        if (Type == 3) {
            for (Edge E : A[From]) {
                if (E.C == '[') {
                    if (!DP[E.To][To][0]) {
                        DP[E.To][To][0] = true;
                        Q.push({E.To,To,0});
                    }
                }
            }
        }
    }
    cout << (DP[S][T][0] ? "Yes" : "No") << endl;
}
}
accuracy: 1
time_ms: 480
memory_kb: 7312
final_rank: 7

code_snippet: #line 2 "cp-library/src/cp-template.hpp"
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
using ld = long double;
using uint = unsigned int;
using ull  = unsigned long long;
using i32 = int;
using u32 = unsigned int;
using i64 = long long;
using u64 = unsigned long long;
using i128 = __int128_t;
template < class T > bool chmin(T& a, T b) { if(a > b) { a = b; return true; } return false; }
template < class T > bool chmax(T& a, T b) { if(a < b) { a = b; return true; } return false; }
template < class T, class U > T ceil (T x, U y) { return (x > 0 ? (x + y - 1) / y :           x / y); }
template < class T, class U > T floor(T x, U y) { return (x > 0 ?           x / y : (x - y + 1) / y); }
int popcnt(i32 x) { return __builtin_popcount(x); }
int popcnt(u32 x) { return __builtin_popcount(x); }
int popcnt(i64 x) { return __builtin_popcountll(x); }
int popcnt(u64 x) { return __builtin_popcountll(x); }

#line 2 "cp-library/src/utility/rep_itr.hpp"
template < class T > struct itr_rep {
    T i, d;
    constexpr itr_rep(const T i) noexcept : i(i), d(1) {}
    constexpr itr_rep(const T i, const T d) noexcept : i(i), d(d) {}
    void operator++() noexcept { i += d; }
    constexpr int operator*() const noexcept { return i; }
    constexpr bool operator!=(const itr_rep x) const noexcept { return d > 0 ? i < x.i : i > x.i; }
};

template < class T > struct rep {
    const itr_rep< T > s, t;
    constexpr rep(const T t) noexcept : s(0), t(t) {}
    constexpr rep(const T s, const T t) noexcept : s(s), t(t) {}
    constexpr rep(const T s, const T t, const T d) noexcept : s(s, d), t(t, d) {}
    constexpr auto begin() const noexcept { return s; }
    constexpr auto end  () const noexcept { return t; }
};

template < class T > struct revrep {
    const itr_rep < T > s, t;
    constexpr revrep(const T t) noexcept : s(t - 1, -1), t(-1, -1) {}
    constexpr revrep(const T s, const T t) noexcept : s(t - 1, -1), t(s - 1, -1) {}
    constexpr revrep(const T s, const T t, const T d) noexcept : s(t - 1, -d), t(s - 1, -d) {}
    constexpr auto begin() const noexcept { return s; }
    constexpr auto end  () const noexcept { return t; }
};
#line 3 "cp-library/src/utility/io.hpp"

/* 128bit integer */
istream& operator>>(istream& is, i128& x) {
    std::string s; is >> s;
    int pm = (s[0] == '-');
    x = 0;
    for(int i : rep(pm, int(s.size()))) x = x * 10 + (s[i] - '0');
    if(pm) x *= -1;
    return is;
}
ostream& operator<<(ostream& os, const i128& x) {
    if(x == 0) return os << '0';
    i128 y = x;
    if(y < 0) { os << '-'; y *= -1; }
    std::vector<int> ny;
    while(y > 0) { ny.push_back(y % 10); y /= 10; }
    for(int i : revrep(ny.size())) os << ny[i];
    return os;
}

template < class S, class T > istream& operator>>(istream& is,       std::pair< S, T >& x) { is >> x.first        >> x.second; return is; }
template < class S, class T > ostream& operator<<(ostream& os, const std::pair< S, T >& x) { os << x.first << " " << x.second; return os; }

namespace scanner {
    struct sca {
        template < class T > operator T() {
            T s; std::cin >> s; return s;
        }
    };
    struct vec {
        int n;
        vec(int n) : n(n) {}
        template < class T > operator std::vector< T >() {
            std::vector< T > v(n);
            for(T& x : v) std::cin >> x;
            return v;
        }
    };
    struct mat {
        int h, w;
        mat(int h, int w) : h(h), w(w) {}
        template < class T > operator std::vector< std::vector< T > >() {
            std::vector m(h, std::vector< T >(w));
            for(std::vector< T >& v : m) for(T& x : v) std::cin >> x;
            return m;
        }
    };
    struct speedup {
        speedup() {
            std::cin.tie(0);
            std::ios::sync_with_stdio(0);
        }
    } speedup_instance;
}
scanner::sca in() { return scanner::sca(); }
scanner::vec in(int n) { return scanner::vec(n); }
scanner::mat in(int h, int w) { return scanner::mat(h, w); }

namespace printer {
    void precision(int d) { std::cout << std::fixed << std::setprecision(d); }
    void flush() { std::cout.flush(); }
}

template < class T >
ostream& operator<<(ostream& os, const std::vector< T > a) {
    int n = a.size();
    for(int i : rep(n)) { os << a[i]; if(i != n - 1) os << ' '; }
    return os;
}

int print() { std::cout << '\n'; return 0; }
template < class head, class... tail > int print(head&& h, tail&&... t) {
    std::cout << h; if(sizeof...(tail)) std::cout << ' ';
    return print(std::forward<tail>(t)...);
}
template < class T > int print_n(const std::vector< T > a) {
    int n = a.size();
    for(int i : rep(n)) std::cout << a[i] << "\n";
    return 0;
}


#line 2 "cp-library/src/utility/key_val.hpp"

template < class K, class V >
struct key_val {
    K key; V val;
    key_val() {}
    key_val(K key, V val) : key(key), val(val) {}
    template < std::size_t Index >
    std::tuple_element_t< Index, key_val >& get() {
        if constexpr (Index == 0) return key;
        if constexpr (Index == 1) return val;
    }
};

namespace std {

template < class K, class V > struct tuple_size < key_val< K, V > > : integral_constant< size_t, 2 > {};
template < class K, class V > struct tuple_element < 0, key_val< K, V > > { using type = K; };
template < class K, class V > struct tuple_element < 1, key_val< K, V > > { using type = V; };

}
#line 2 "cp-library/src/utility/vec_op.hpp"
template < class T > key_val< int, T > max_of(const vector< T >& a) {
    int i = std::max_element(a.begin(), a.end()) - a.begin();
    return {i, a[i]};
}
template < class T > key_val< int, T > min_of(const vector< T >& a) {
    int i = std::min_element(a.begin(), a.end()) - a.begin();
    return {i, a[i]};
}
template < class S, class T > S sum_of(const vector< T >& a) {
    S sum = 0;
    for(const T x : a) sum += x;
    return sum;
}
template < class S, class T > vector< S > freq_of(const vector< T >& a, T L, T R) {
    vector< S > res(R - L, S(0));
    for(const T x : a) res[x - L] += 1;
    return res;
}
template < class S, class T > struct prefix_sum {
    vector< S > s;
    prefix_sum(const vector< T >& a) : s(a) {
        s.insert(s.begin(), S(0));
        for(int i : rep(a.size())) s[i + 1] += s[i];
    }
    // [L, R)
    S sum(int L, int R) { return s[R] - s[L]; }
};
#line 3 "cp-library/src/utility/heap.hpp"

template < class T > using heap_min = std::priority_queue< T, std::vector< T >, std::greater< T > >;
template < class T > using heap_max = std::priority_queue< T, std::vector< T >, std::less< T > >;

#line 27 "cp-library/src/cp-template.hpp"

#line 1 "cp-library/src/algorithm/bin_search.hpp"
template < class T, class F >
T bin_search(T ok, T ng, F f) {
    while(abs(ng - ok) > 1) {
        T mid = (ok + ng) / 2;
        (f(mid) ? ok : ng) = mid;
    }
    return ok;
}

template < class T, class F >
T bin_search_real(T ok, T ng, F f, int step = 80) {
    while(step--) {
        T mid = (ok + ng) / 2;
        (f(mid) ? ok : ng) = mid;
    }
    return ok;
}
#line 2 "cp-library/src/algorithm/argsort.hpp"

template < class T > std::vector< int > argsort(const std::vector< T > &a) {
    std::vector< int > ids((int)a.size());
    std::iota(ids.begin(), ids.end(), 0);
    std::sort(ids.begin(), ids.end(), [&](int i, int j) {
        return a[i] < a[j] || (a[i] == a[j] && i < j);
    });
    return ids;
}
#line 1 "macro.hpp"
namespace macro {

using size_type = int;
template < class container > void  sort(container& a) { std::sort(std:: begin(a), std:: end(a)); }
template < class container > void rsort(container& a) { std::sort(std::rbegin(a), std::rend(a)); }
template < class container > void reverse(container& a) { std::reverse(std::begin(a), std::end(a)); }
template < class container > void unique(container& a) {
    std::sort(std::begin(a), std::end(a));
    a.erase(std::unique(std::begin(a), std::end(a)), std::end(a));
}
template < class container > container  sorted(const container& a) { container b = a;  sort(b); return std::move(b); }
template < class container > container rsorted(const container& a) { container b = a; rsort(b); return std::move(b); }
template < class container, class compare > void sort(container& a, const compare& cmp) { std::sort(std::begin(a), std::end(a), cmp); }
template < class container, class compare > container sorted(const container& a, const compare& cmp) { container b = a; sort(b, cmp); return std::move(b); }
template < class container, class value > size_type lower_bound(const container& a, const value& x) { return std::lower_bound(std::begin(a), std::end(a), x) - std::begin(a); }
template < class container, class value > size_type upper_bound(const container& a, const value& x) { return std::upper_bound(std::begin(a), std::end(a), x) - std::begin(a); }

const std::vector<std::pair<size_type, size_type>> dir4 = { {+1,  0}, {-1,  0}, { 0, +1}, { 0, -1} };
const std::vector<std::pair<size_type, size_type>> dir8 = { {-1, -1}, {-1,  0}, {-1, +1}, { 0, -1}, { 0, +1}, {+1, -1}, {+1,  0}, {+1, +1} };

#ifdef _DEBUG
#define debug(x) std::cout << "[" << __LINE__ << "] " << #x << ": " << x << std::endl
#else
#define debug(x)
#endif

template < class container > void concat(container& a, const container& b) {
    a.insert(std::end(a), std::begin(b), std::end(b));
}
std::vector<size_type> iota(const size_type n) {
    std::vector<size_type> I(n);
    std::iota(std::begin(I), std::end(I), 0);
    return I;
}
template < class container > std::vector<size_type> sort_idx(const container& a) {
    const size_type n = a.size();
    std::vector<size_type> I = iota(n);
    std::sort(std::begin(I), std::end(I), [&](size_type i, size_type j) { return a[i] < a[j] or (a[i] == a[j] and i < j); });
    return I;
}
template < class container, class compare > std::vector<size_type> sort_idx(const container& a, const compare& cmp) {
    const size_type n = a.size();
    std::vector<size_type> I = iota(n);
    std::sort(std::begin(I), std::end(I), [&](size_type i, size_type j) { return cmp(a[i], a[j]) or (a[i] == a[j] and i < j); });
    return std::move(I);
}

struct grid {
    using size_type = int;
    size_type H, W;
    grid(const size_type H, const size_type W) : H(H), W(W) {}
    bool contains(const size_type i, const size_type j) {
        return 0 <= i and i < H and 0 <= j and j < W;
    }
};

using f64 = long double;

template < class T > vector< T >& operator++(vector< T >& a) { for(T& x : a) x++; return a; }
template < class T > vector< T >& operator--(vector< T >& a) { for(T& x : a) x--; return a; }
template < class T > vector< T >  operator++(vector< T >& a, signed) { vector< T > res = a; for(T& x : a) x++; return res; }
template < class T > vector< T >  operator--(vector< T >& a, signed) { vector< T > res = a; for(T& x : a) x--; return res; }

} // namespace macro

using namespace macro;
#line 3 "A.cpp"

bool solve(int n, int m, int s, int t) {
    s--, t--;
    vector edge(n, vector(n, map<char,bool>{}));
    vector dp(4, vector(n, vector(n, -1)));
    enum { expr, op_expr, expr_a, expr_b };
    queue<tuple<int,int,int>> q;
    for(int _ : rep(m)) {
        int a = in(), b = in(); char c = in(); a--, b--;
        edge[a][b][c] = true;
        if(c == 'a') q.push({expr, a, b});
    }

    while(not q.empty()) {
        auto [i, u, v] = q.front(); q.pop();
        if(dp[i][u][v] != -1) continue;
        dp[i][u][v] = 1;
        if(i == expr) {
            // expr -> expr op_expr
            // expr_a -> expr )
            // expr_b -> expr ]
            for(int w : rep(n)) {
                if(dp[op_expr][v][w] == 1 and dp[expr][u][w] == -1) q.push({expr, u, w});
                if(edge[v][w][')'] and dp[expr_a][u][w] == -1) q.push({expr_a, u, w});
                if(edge[v][w][']'] and dp[expr_b][u][w] == -1) q.push({expr_b, u, w});
            }
            // op_expr -> op expr
            for(int t : rep(n)) {
                if(edge[t][u]['+'] and dp[op_expr][t][v] == -1) q.push({op_expr, t, v});
                if(edge[t][u]['*'] and dp[op_expr][t][v] == -1) q.push({op_expr, t, v});
            }
        }
        if(i == op_expr) {
            // expr -> expr op_expr
            for(int t :  rep(n)) {
                if(dp[expr][t][u] == 1 and dp[expr][t][v] == -1) q.push({expr, t, v});
            }
        }
        if(i == expr_a) {
            // expr -> ( expr_a
            for(int t : rep(n)) {
                if(edge[t][u]['('] and dp[expr][t][v] == -1) q.push({expr, t, v});
            }
        }
        if(i == expr_b) {
            // expr -> [ expr_b
            for(int t : rep(n)) {
                if(edge[t][u]['['] and dp[expr][t][v] == -1) q.push({expr, t, v});
            }
        }
    }
    return dp[expr][s][t] == 1;
}

int main() {
    while(true) {
        int n = in(), m = in(), s = in(), t = in();
        if(make_tuple(n, m, s, t) == make_tuple(0, 0, 0, 0)) return 0;
        print(solve(n, m, s, t) ? "Yes" : "No");
    }
}
accuracy: 1
time_ms: 2590
memory_kb: 105776
final_rank: 20

code_snippet: #include<bits/stdc++.h>
using namespace std;
using ll = long long;
using vll = vector<ll>;
#define rep(i,n) for(ll i=0;i<n;i++)
#define all(A) A.begin(),A.end()

/*
    exp= 0
    op= 1
    ( = 2
    [ = 3
    ) = 4
    ] = 5
    op exp = 6
    ( exp = 7
    [ exp = 8
*/

// d e　をつなげると?
void init(vector<vector<pair<ll,ll>>> &F,vector<vector<pair<ll,ll>>> &IF){
    F.resize(9);
    IF.resize(9);
    rep(i,3){
        F[i+1].push_back({0,i+6});
        IF[0].push_back({i+1,i+6});
    }
    rep(i,2){
        F[i+7].push_back({i+4,0});
        IF[i+4].push_back({i+7,0});
    }
    F[0].push_back({6,0});
    IF[6].push_back({0,0});
}
void solve(ll N,ll M,ll S,ll T) {

    vector<vector<vector<bool>>> seen(N,vector<vector<bool>>(N,vector<bool>(10,0)));
    queue<pair<pair<ll,ll>,ll>>Q;
    vector<vector<pair<ll,ll>>> F,IF;
    init(F,IF);
    string ST="a+([)]";
    rep(i,M){
        ll a,b;
        char c;
        cin>>a>>b>>c;
        if(c=='*')c='+';
        a--;b--;
        rep(j,6)if(c==ST[j]&&!seen[a][b][j]){
            Q.push({{a,b},j});
            seen[a][b][j]=1;
        }
    }
        
    while (!Q.empty()) {
        ll a = Q.front().first.first;
        ll b = Q.front().first.second;
        ll c = Q.front().second;
        Q.pop();
        for(auto [d,nc]:F[c])rep(nb,N){
            if(!seen[b][nb][d]||seen[a][nb][nc])continue;
            seen[a][nb][nc]=1;
            Q.push({{a,nb},nc});            
        }
        for(auto [d,nc]:IF[c])rep(na,N){
            if(!seen[na][a][d]||seen[na][b][nc])continue;
            seen[na][b][nc]=1;
            Q.push({{na,b},nc});
        }
    }
    cout<<(seen[S][T][0]?"Yes":"No")<<endl;
}

int main() {
    ll N,M,S,T;
    while(cin>>N>>M>>S>>T,N!=0)solve(N,M,S-1,T-1);
}
accuracy: 1
time_ms: 890
memory_kb: 11284
final_rank: 14

code_snippet: #include<bits/stdc++.h>
using namespace std;
using ll = long long;
using vll = vector<ll>;
#define rep(i,n) for(ll i=0;i<n;i++)
#define all(A) A.begin(),A.end()

/*
    exp= 0
    op= 1
    ( = 2
    [ = 3
    ) = 4
    ] = 5
    op exp = 6
    ( exp = 7
    [ exp = 8
*/

// d e　をつなげると?
void init(vector<vector<pair<ll,ll>>> &F,vector<vector<pair<ll,ll>>> &IF){
    F.resize(9);
    IF.resize(9);
    rep(i,3){
        F[i+1].push_back({0,i+6});
        IF[0].push_back({i+1,i+6});
    }
    rep(i,2){
        F[i+7].push_back({i+4,0});
        IF[i+4].push_back({i+7,0});
    }
    F[0].push_back({6,0});
    IF[6].push_back({0,0});
}
void solve(ll N,ll M,ll S,ll T) {

    vector<vector<vector<bool>>> seen(N,vector<vector<bool>>(N,vector<bool>(10,0)));
    queue<pair<pair<ll,ll>,ll>>Q;
    vector<vector<pair<ll,ll>>> F,IF;
    init(F,IF);
    string ST="a+([)]";
    rep(i,M){
        ll a,b;
        char c;
        cin>>a>>b>>c;
        if(c=='*')c='+';
        a--;b--;
        rep(j,6)if(c==ST[j]&&!seen[a][b][j]){
            Q.push({{a,b},j});
            seen[a][b][j]=1;
        }
    }
        
    while (!Q.empty()) {
        ll a = Q.front().first.first;
        ll b = Q.front().first.second;
        ll c = Q.front().second;
        Q.pop();
        for(auto [d,nc]:F[c])rep(nb,N){
            if(!seen[b][nb][d])continue;
            if(seen[a][nb][nc])continue;
            seen[a][nb][nc]=1;
            Q.push({{a,nb},nc});            
        }
        for(auto [d,nc]:IF[c])rep(na,N){
            if(!seen[na][a][d])continue;
            if(seen[na][b][nc])continue;
            seen[na][b][nc]=1;
            Q.push({{na,b},nc});
        }
    }
    cout<<(seen[S][T][0]?"Yes":"No")<<endl;
}

int main() {
    cin.tie(nullptr);
    ios::sync_with_stdio(false);
    ll N,M,S,T;
    while(cin>>N>>M>>S>>T,N!=0){
        // clock_t start=clock();
        solve(N,M,S-1,T-1);
        // clock_t end=clock();
        // cout<<fixed<<setprecision(15)<<double(end-start)/CLOCKS_PER_SEC<<endl;
    }
}
accuracy: 1
time_ms: 770
memory_kb: 11300
final_rank: 13

code_snippet: #include <bits/stdc++.h>

constexpr int N = 205;

int solve() {
    int n, m, s, t;
    std::cin >> n >> m >> s >> t;
    if (n == 0) return 1;
    s--; t--;
    using Bitset = std::bitset<N>;
    std::vector<Bitset> state(n);
    int mapping[256] = {};
    const int W = 7;
    const char set[] = {'a', '(', ')', '[', ']', '+', '*'};
    for (int i = 0; i < W; i++) mapping[set[i]] = i;

    std::vector graph(n, std::vector(W, std::vector<int>()));
    for (int i = 0; i < m; i++) {
        int u, v;
        char c;
        std::cin >> u >> v >> c;
        u--; v--;
        if (c == '(' || c == '[') {
            graph[v][mapping[c]].push_back(u);
        } else {
            graph[u][mapping[c]].push_back(v);
        }
    }

    for (int i = 0; i < n; i++) {
        for (auto v: graph[i][mapping['a']]) {
            state[i].set(v);
        }
    }

    std::vector<int> prev(n);
    for (int i = 0; i < n; i++) {
        prev[i] = state[i].count();
    }
    while (true) {
        if (state[s][t]) break;
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < n; j++) {
                if (!state[i][j]) continue;
                for (auto c: {'+', '*'}) {
                    for (int k: graph[j][mapping[c]]) {
                        state[i] |= state[k];
                    }
                }
            }
        }
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < n; j++) {
                if (!state[i][j]) continue;
                for (int k: graph[i][mapping['(']]) {
                    for (int l: graph[j][mapping[')']]) {
                        state[k].set(l);
                    }
                }
                for (int k: graph[i][mapping['[']]) {
                    for (int l: graph[j][mapping[']']]) {
                        state[k].set(l);
                    }
                }
            }
        }
        bool ok = false;
        for (int i = 0; i < n; i++) {
            int v = state[i].count();
            ok |= v != prev[i];
            prev[i] = v;
        }
        if (!ok) break;
    }
    std::cout << (state[s][t] ? "Yes" : "No") << std::endl;
    return 0;
}

int main() {
    while (!solve());
}
accuracy: 1
time_ms: 670
memory_kb: 4116
final_rank: 6

code_snippet: #ifdef RELEASE
#pragma GCC target("arch=x86-64-v3")
#pragma GCC optimize("Ofast")
#endif

#include <bits/stdc++.h>

//#include <atcoder/all>


using namespace std;

using ll = long long;
using i64 = long long;
using pll = pair<ll,ll>;
using plll = pair<pll,ll>;

constexpr ll mod = 998244353;


int main(){
  while (true){
    int n, m, s, t;
    cin >> n >> m >> s >> t;
    if(n == 0)break;
    --s, --t ;
    vector<vector<int>> edges_Bopen(n);
    vector<vector<int>> edges_Bclose(n);
    vector<vector<int>> edges_Copen(n);
    vector<vector<int>> edges_Cclose(n);
    vector<vector<int>> edges_D(n);
    queue<tuple<int,int,int>> que;
    vector<vector<vector<int>>> dp(n, vector<vector<int>>(n, vector<int>(4, 0)));
    auto add = [&](int l, int r, int ty){
      if(!dp[l][r][ty]){
//        cout << 1 + l << " " << 1 + r << " " << ty << endl;
        dp[l][r][ty] = true;
        que.emplace(l, r, ty);
      }
    };
    for(int i = 0; i < m; ++i){
      int u, v;
      char c;
      cin >> u >> v >> c;
      --u, --v;
      if(c == 'a'){
        add(u, v, 0);
      }
      if(c == '['){
        edges_Copen[v].emplace_back(u);
      }
      if(c == '('){
        edges_Bopen[v].emplace_back(u);
      }
      if(c == ']'){
        edges_Cclose[u].emplace_back(v);
      }
      if(c == ')'){
        edges_Bclose[u].emplace_back(v);
      }
      if(c == '+' || c == '*'){
        edges_D[u].emplace_back(v);
      }
    }

    while(!que.empty()){
      auto [l, r, typ] = que.front();
      que.pop();
      if(typ == 0){
        for(auto w : edges_Bclose[r]){
          add(l, w, 1);
        }
        for(auto w : edges_Cclose[r]){
          add(l, w, 2);
        }
        for(auto w : edges_D[r]){
          add(l, w, 3);
        }
        for(int w = 0; w < n; ++w){
          if(dp[w][l][3]){
            add(w, r, 0);
          }
        }
      }
      if(typ == 1){
        for(auto w : edges_Bopen[l]){
          add(w, r, 0);
        }
      }
      if(typ == 2){
        for(auto w : edges_Copen[l]){
          add(w, r, 0);
        }
      }
      if(typ == 3){
        for(int w = 0; w < n; ++w){
          if(dp[r][w][0]){
            add(l, w, 0);
          }
        }
      }
    }
    cout << (dp[s][t][0] ? "Yes" : "No") << endl;
  }
}
accuracy: 1
time_ms: 350
memory_kb: 7896
final_rank: 4

code_snippet: #include <bits/stdc++.h>
using namespace std;
#define REP(i, n) for (int i = 0; i < (n); i++)
template <class T> ostream &operator<<(ostream &os, vector<T> &v) {
    os << "[ ";
    for (auto &vi : v) os << vi << " ";
    return os << "]";
}
#define show(x) cerr << __LINE__ << " : " << #x << " = " << x << endl;
//#define show(x) true
template <class T, class U> bool chmax(T &a, const U &b) {
    if (a < b) {
        a = b;
        return 1;
    }
    return 0;
}

void solve(int N, int M, int S, int T) {
    // {0,     1,     2,     3,  4,  5,  6,  7,  8,  9,      10,     11,     12   }
    // {expr,  term,  fact,  (,  ),  [,  ],  +,  *,  expr+,  term*,  (expr,  [expr}
    vector dp(13, vector(N, vector<int>(N))), seen(13, vector(N, vector<int>(N)));
    vector<int> A(M), B(M);
    vector<char> C(M);
    queue<tuple<int, int, int>> que;
    string stamp = "a()[]+*";
    REP(i, M) {
        cin >> A[i] >> B[i] >> C[i];
        A[i]--, B[i]--;
        REP(j, 7) {
            if (C[i] == stamp[j]) {
                dp[j + 2][A[i]][B[i]] = 1;
                que.push({j + 2, A[i], B[i]});
            }
        }
    }
    
    while(!que.empty()) {
        auto [i, a, b] = que.front();
        que.pop();
        if (seen[i][a][b]) continue;
        seen[i][a][b] = 1;
        auto f = [&](int l, int m, int r, int t1, int t2, int t3) {
            if (dp[t1][l][m] and dp[t2][m][r] and chmax(dp[t3][l][r], 1)) que.push({t3, l, r});
        };
        if (i == 0) { // expr
            REP(x, N) f(a, b, x, i, 7, 9);  // expr+
            REP(x, N) f(x, a, b, 3, i, 11); // (expr
            REP(x, N) f(x, a, b, 5, i, 12); // [expr
        }
        if (i == 1) { // term
            if (chmax(dp[0][a][b], 1)) que.push({0, a, b}); // expr
            REP(x, N) f(a, b, x, i, 8, 10); // term*
            REP(x, N) f(x, a, b, 9, i, 0);  // expr = expr+ term
        }
        if (i == 2) { // fact
            if (chmax(dp[1][a][b], 1)) que.push({1, a, b}); // term
            REP(x, N) f(x, a, b, 10, i, 1); // term = term* fact
        }
        if (i == 9) { // expr+
            REP(x, N) f(a, b, x, i, 1, 0); // expr = expr+ term
        }
        if (i == 10) { // term*
            REP(x, N) f(a, b, x, i, 2, 1); // term = term* fact
        }
        if (i == 11) { // (expr
            REP(x, N) f(a, b, x, i, 4, 2); // factor = (expr )
        }
        if (i == 12) { // [expr
            REP(x, N) f(a, b, x, i, 6, 2); // factor = [expr ]
        }
    }
    S--, T--;
    cout << (dp[0][S][T] ? "Yes": "No") << endl;
}

int main() {
    int N, M, S, T;
    while (cin >> N >> M >> S >> T, !(N == 0 and M == 0 and S == 0 and T == 0)) solve(N, M, S, T);
    return 0;
}
accuracy: 1
time_ms: 710
memory_kb: 10572
final_rank: 12

code_snippet: #include <bits/stdc++.h>
using namespace std;
#define REP(i, n) for (int i = 0; i < (n); i++)
template <class T> ostream &operator<<(ostream &os, vector<T> &v) {
    os << "[ ";
    for (auto &vi : v) os << vi << " ";
    return os << "]";
}
#define show(x) cerr << __LINE__ << " : " << #x << " = " << x << endl;
//#define show(x) true
template <class T, class U> bool chmax(T &a, const U &b) {
    if (a < b) {
        a = b;
        return 1;
    }
    return 0;
}

void solve(int N, int M, int S, int T) {
    // {0,     1,     2,     3,  4,  5,  6,  7,  8,  9,      10,     11,     12   }
    // {expr,  term,  fact,  (,  ),  [,  ],  +,  *,  expr+,  term*,  (expr,  [expr}
    vector dp(13, vector(N, vector<int>(N))), seen(13, vector(N, vector<int>(N)));
    vector<int> A(M), B(M);
    vector<char> C(M);
    queue<tuple<int, int, int>> que;
    string stamp = "a()[]+*";
    REP(i, M) {
        cin >> A[i] >> B[i] >> C[i];
        A[i]--, B[i]--;
        REP(j, 7) {
            if (C[i] == stamp[j]) {
                dp[j + 2][A[i]][B[i]] = 1;
                que.push({j + 2, A[i], B[i]});
            }
        }
    }
    while(!que.empty()) {
        auto [i, a, b] = que.front();
        que.pop();
        if (seen[i][a][b]) continue;
        seen[i][a][b] = 1;
        if (i == 0) {
            // expr
            REP(x, N) {
                // expr+
                if (dp[7][b][x] and chmax(dp[9][a][x], 1)) que.push({9, a, x});
                // (expr
                if (dp[3][x][a] and chmax(dp[11][x][b], 1)) que.push({11, x, b});
                // [expr
                if (dp[5][x][a] and chmax(dp[12][x][b], 1)) que.push({12, x, b});
            }
        }
        if (i == 1) {
            // term
            // expr
            if (chmax(dp[0][a][b], 1)) que.push({0, a, b});
            REP(x, N) {
                // term*
                if (dp[8][b][x] and chmax(dp[10][a][x], 1)) que.push({10, a, x});
                // expr = expr+ term
                if (dp[9][x][a] and chmax(dp[0][x][b], 1)) que.push({0, x, b});
            }
        }
        if (i == 2) {
            // fact
            // term
            if (chmax(dp[1][a][b], 1)) que.push({1, a, b});
            REP(x, N) {
                // term = term* fact
                if (dp[10][x][a] and chmax(dp[1][x][b], 1)) que.push({1, x, b});
            }
        }
        if (i == 9) {
            // expr+
            REP(x, N) {
                // expr = expr+ term
                if (dp[1][b][x] and chmax(dp[0][a][x], 1)) que.push({0, a, x});
            }
        }
        if (i == 10) {
            // term*
            REP(x, N) {
                // term = term* fact
                if (dp[2][b][x] and chmax(dp[1][a][x], 1)) que.push({1, a, x});
            }
        }
        if (i == 11) {
            // (expr
            REP(x, N) {
                // factor = (expr )
                if (dp[4][b][x] and chmax(dp[2][a][x], 1)) que.push({2, a, x});
            }
        }
        if (i == 12) {
            // [expr
            REP(x, N) {
                // factor = [expr ]
                if (dp[6][b][x] and chmax(dp[2][a][x], 1)) que.push({2, a, x});
            }
        }
    }
    S--, T--;
    cout << (dp[0][S][T] ? "Yes": "No") << endl;
}

int main() {
    int N, M, S, T;
    while (cin >> N >> M >> S >> T, !(N == 0 and M == 0 and S == 0 and T == 0)) solve(N, M, S, T);
    return 0;
}
accuracy: 1
time_ms: 660
memory_kb: 10488
final_rank: 10

code_snippet: #include <bits/stdc++.h>
using namespace std;
#define REP(i, n) for (int i = 0; i < (n); i++)
template <class T> ostream &operator<<(ostream &os, vector<T> &v) {
    os << "[ ";
    for (auto &vi : v) os << vi << " ";
    return os << "]";
}
#define show(x) cerr << __LINE__ << " : " << #x << " = " << x << endl;
//#define show(x) true
template <class T, class U> bool chmax(T &a, const U &b) {
    if (a < b) {
        a = b;
        return 1;
    }
    return 0;
}

void solve(int N, int M, int S, int T) {
    // {0,           1,     2,       3,  4,  5,  6,  7,  8,  9,      10,     11,     12   }
    // {expression,  term,  factor,  (,  ),  [,  ],  +,  *,  expr+,  term*,  (expr,  [expr}
    vector dp(13, vector(N, vector<int>(N))), seen(13, vector(N, vector<int>(N)));
    vector<int> A(M), B(M);
    vector<char> C(M);
    queue<tuple<int, int, int>> que;
    string stamp = "a()[]+*";
    REP(i, M) {
        cin >> A[i] >> B[i] >> C[i];
        A[i]--, B[i]--;
        REP(j, 7) {
            if (C[i] == stamp[j]) {
                dp[j + 2][A[i]][B[i]] = 1;
                que.push({j + 2, A[i], B[i]});
            }
        }
    }
    while(!que.empty()) {
        auto [i, a, b] = que.front();
        que.pop();
        if (seen[i][a][b]) continue;
        seen[i][a][b] = 1;
        if (i == 0) {
            // expression
            REP(x, N) {
                if (dp[7][b][x] and chmax(dp[9][a][x], 1)) que.push({9, a, x});
                if (dp[3][x][a] and chmax(dp[11][x][b], 1)) que.push({11, x, b});
                if (dp[5][x][a] and chmax(dp[12][x][b], 1)) que.push({12, x, b});
            }
        }
        if (i == 1) {
            // term
            if (chmax(dp[0][a][b], 1)) que.push({0, a, b});
            REP(x, N) {
                if (dp[8][b][x] and chmax(dp[10][a][x], 1)) que.push({10, a, x});
                if (dp[9][x][a] and chmax(dp[0][x][b], 1)) que.push({0, x, b});
            }
        }
        if (i == 2) {
            // factor
            if (chmax(dp[1][a][b], 1)) que.push({1, a, b});
            REP(x, N) {
                if (dp[10][x][a] and chmax(dp[1][x][b], 1)) que.push({1, x, b});
            }
        }
        if (i == 9) {
            // expr+
            REP(x, N) {
                if (dp[1][b][x] and chmax(dp[0][a][x], 1)) que.push({0, a, x});
            }
        }
        if (i == 10) {
            // term*
            REP(x, N) {
                if (dp[2][b][x] and chmax(dp[1][a][x], 1)) que.push({1, a, x});
            }
        }
        if (i == 11) {
            // (expr
            REP(x, N) {
                if (dp[4][b][x] and chmax(dp[2][a][x], 1)) que.push({2, a, x});
            }
        }
        if (i == 12) {
            // [expr
            REP(x, N) {
                if (dp[6][b][x] and chmax(dp[2][a][x], 1)) que.push({2, a, x});
            }
        }
    }
    S--, T--;
    cout << (dp[0][S][T] ? "Yes": "No") << endl;
}

int main() {
    int N, M, S, T;
    while (cin >> N >> M >> S >> T, !(N == 0 and M == 0 and S == 0 and T == 0)) solve(N, M, S, T);
    return 0;
}
accuracy: 1
time_ms: 660
memory_kb: 10620
final_rank: 11

code_snippet: #include <bits/stdc++.h>

using namespace std;
using ll = long long;
using pii = pair<int, int>;
using pic = pair<int, char>;
using vi = vector<int>;
using vvi = vector<vi>;
using vvvi = vector<vvi>;

int ini() {
    int n;
    cin >> n;
    return n;
}

const int inf = 1000000;
bool solve(){
    int n = ini();
    if (n == 0) {
        return true;
    }
    int m = ini();
    int s = ini() - 1;
    int t = ini() - 1;
    vvi edgesPl(n);
    vvi edgesPr(n);
    vvi edgesQl(n);
    vvi edgesQr(n);
    vvi edgesO(n);
    vvi t0(n, vi(n, 0));
    vvi t1(n, vi(n, 0));
    vvi t2(n, vi(n, 0));
    vvi t3(n, vi(n, 0));
    vector<set<int>> t0s(n);
    vector<set<int>> t1s(n);
    vector<set<int>> t2s(n);
    vector<set<int>> t3s(n);
    deque<pii> deq;
    for (int i = 0; i < m; i++) {
        int a = ini() - 1;
        int b = ini() - 1;
        string c;
        cin >> c;
        if (c[0] == 'a') {
            t0[a][b] = 1;
            deq.emplace_back(a, b);
            t0s[b].emplace(a);
        } else if (c[0] == '+' || c[0] == '*') {
            edgesO[b].push_back(a);
        } else if (c[0] == '(') {
            edgesPl[b].push_back(a);
        } else if (c[0] == ')') {
            edgesPr[a].push_back(b);
        } else if (c[0] == '[') {
            edgesQl[b].push_back(a);
        } else if (c[0] == ']') {
            edgesQr[a].push_back(b);
        }
    }
    for (int i = 0; i < n; i++) {
        edgesPl[i].erase(unique(edgesPl[i].begin(), edgesPl[i].end()), edgesPl[i].end());
        edgesPr[i].erase(unique(edgesPr[i].begin(), edgesPr[i].end()), edgesPr[i].end());
        edgesQl[i].erase(unique(edgesQl[i].begin(), edgesQl[i].end()), edgesQl[i].end());
        edgesQr[i].erase(unique(edgesQr[i].begin(), edgesQr[i].end()), edgesQr[i].end());
        edgesO[i].erase(unique(edgesO[i].begin(), edgesO[i].end()), edgesO[i].end());
    }
    while (!deq.empty()) {
        pii p = deq.front();
        deq.pop_front();
        if (p.second < n) {
            for (int i : edgesPl[p.first]) {
                if (t2[i][p.second] == 0) {
                    t2[i][p.second] = 1;
                    deq.emplace_back(i, p.second+n*2);
                    t2s[p.second].emplace(i);
                }
            }
            for (int i : edgesQl[p.first]) {
                if (t3[i][p.second] == 0) {
                    t3[i][p.second] = 1;
                    deq.emplace_back(i, p.second+n*3);
                    t3s[p.second].emplace(i);
                }
            }
            for (int i : edgesO[p.first]) {
                if (t1[i][p.second] == 0) {
                    t1[i][p.second] = 1;
                    deq.emplace_back(i, p.second+n);
                    t1s[i].emplace(p.second);
                }
            }
            // cout << "!" << p.first << endl;
            // for (int i = 0; i < t1s[p.first].size(); i++) cout << t1s[p.first][i] << " \n"[i+1==t1s[p.first].size()];
            for (int i : t1s[p.second]) {
                if (t0[p.first][i] == 0) {
                    t0[p.first][i] = 1;
                    deq.emplace_back(p.first, i);
                    t0s[i].emplace(p.first);
                }
            }
        } else if (p.second < n * 2) {
            int sec = p.second - n;
            // cout << "?" << endl;
            // for (int i = 0; i < t0s[p.first].size(); i++) cout << t0s[p.first][i] << " \n"[i+1==t0s[p.first].size()];
            for (int i : t0s[p.first]) {
                if (t0[i][sec] == 0) {
                    t0[i][sec] = 1;
                    deq.emplace_back(i, sec);
                    t0s[sec].emplace(i);
                }
            }
        } else if (p.second < n * 3) {
            int sec = p.second - n*2;
            for (int j : edgesPr[sec]) {
                if (t0[p.first][j] == 0) {
                    t0[p.first][j] = 1;
                    deq.emplace_back(p.first, j);
                    t0s[j].emplace(p.first);
                }
            }
        } else {
            int sec = p.second - n*3;
            for (int j : edgesQr[sec]) {
                if (t0[p.first][j] == 0) {
                    t0[p.first][j] = 1;
                    deq.emplace_back(p.first, j);
                    t0s[j].emplace(p.first);
                }
            }
        }
    }
    // for (int i = 0; i < n; i++) {
    //     for (int j = 0; j < n; j++) {
    //         cout << t0[i][j] << " ";
    //     }
    //     cout << endl;
    // }
    // cout << endl;
    // for (int i = 0; i < n; i++) {
    //     for (int j = 0; j < n; j++) {
    //         cout << t1[i][j] << " ";
    //     }
    //     cout << endl;
    // }
    cout << (t0[s][t] == 1 ? "Yes" : "No") << endl;
    return false;
}

int main(){
    while(!solve());
}
accuracy: 1
time_ms: 970
memory_kb: 13016
final_rank: 15

code_snippet: #pragma region Macros
#if defined(noimi) && defined(_GLIBCXX_DEBUG) && defined(_GLIBCXX_DEBUG_PEDANTIC)
// #pragma comment(linker, "/stack:200000000")
#include <stdc++.h>
#pragma GCC optimize("O3")
#else
#pragma GCC optimize("Ofast")
// #pragma GCC optimize("unroll-loops")
// #pragma GCC target("popcnt")
// #pragma GCC target("sse,sse2,sse3,ssse3,sse4,popcnt,fma,abm,mmx,avx,avx2,tune=native")
// #pragma GCC target("sse,sse2,sse3,ssse3,sse4,popcnt,fma,abm,mmx,avx,avx2")
// #pragma GCC target("avx2")
#include <bits/stdc++.h>
#endif

#ifdef noimi
#define oj_local(a, b) b
#else
#define oj_local(a, b) a
#endif

#define LOCAL if(oj_local(0, 1))
#define OJ if(oj_local(1, 0))

using namespace std;
using ll = long long;
using ull = unsigned long long int;
using i128 = __int128_t;
using pii = pair<int, int>;
using pll = pair<ll, ll>;
using ld = long double;
template <typename T> using vc = vector<T>;
template <typename T> using vvc = vector<vc<T>>;
template <typename T> using vvvc = vector<vvc<T>>;
using vi = vc<int>;
using vl = vc<ll>;
using vpi = vc<pii>;
using vpl = vc<pll>;
template <class T> using pq = priority_queue<T>;
template <class T> using pqg = priority_queue<T, vector<T>, greater<T>>;
template <typename T> int si(const T &x) { return x.size(); }
template <class T, class S> inline bool chmax(T &a, const S &b) { return (a < b ? a = b, 1 : 0); }
template <class T, class S> inline bool chmin(T &a, const S &b) { return (a > b ? a = b, 1 : 0); }
vi iota(int n) {
    vi a(n);
    return iota(a.begin(), a.end(), 0), a;
}
template <typename T> vi iota(const vector<T> &a, bool greater = false) {
    vi res(a.size());
    iota(res.begin(), res.end(), 0);
    sort(res.begin(), res.end(), [&](int i, int j) {
        if(greater) return a[i] > a[j];
        return a[i] < a[j];
    });
    return res;
}

// macros
#define overload5(a, b, c, d, e, name, ...) name
#define overload4(a, b, c, d, name, ...) name
#define endl '\n'
#define REP0(n) for(ll jidlsjf = 0; jidlsjf < n; ++jidlsjf)
#define REP1(i, n) for(ll i = 0; i < (n); ++i)
#define REP2(i, a, b) for(ll i = (a); i < (b); ++i)
#define REP3(i, a, b, c) for(ll i = (a); i < (b); i += (c))
#define rep(...) overload4(__VA_ARGS__, REP3, REP2, REP1, REP0)(__VA_ARGS__)
#define per0(n) for(int jidlsjf = 0; jidlsjf < (n); ++jidlsjf)
#define per1(i, n) for(ll i = (n)-1; i >= 0; --i)
#define per2(i, a, b) for(ll i = (a)-1; i >= b; --i)
#define per3(i, a, b, c) for(ll i = (a)-1; i >= (b); i -= (c))
#define per(...) overload4(__VA_ARGS__, per3, per2, per1, per0)(__VA_ARGS__)
#define fore0(a) rep(a.size())
#define fore1(i, a) for(auto &&i : a)
#define fore2(a, b, v) for(auto &&[a, b] : v)
#define fore3(a, b, c, v) for(auto &&[a, b, c] : v)
#define fore4(a, b, c, d, v) for(auto &&[a, b, c, d] : v)
#define fore(...) overload5(__VA_ARGS__, fore4, fore3, fore2, fore1, fore0)(__VA_ARGS__)
#define fi first
#define se second
#define pb push_back
#define ppb pop_back
#define ppf pop_front
#define eb emplace_back
#define drop(s) cout << #s << endl, exit(0)
#define si(c) (int)(c).size()
#define lb(c, x) distance((c).begin(), lower_bound(all(c), (x)))
#define ub(c, x) distance((c).begin(), upper_bound(all(c), (x)))
#define rng(v, l, r) v.begin() + l, v.begin() + r
#define all(c) begin(c), end(c)
#define rall(c) rbegin(c), rend(c)
#define SORT(v) sort(all(v))
#define REV(v) reverse(all(v))
#define UNIQUE(x) SORT(x), x.erase(unique(all(x)), x.end())
template <typename T = ll, typename S> T SUM(const S &v) { return accumulate(all(v), T(0)); }
#define MIN(v) *min_element(all(v))
#define MAX(v) *max_element(all(v))
#define overload2(_1, _2, name, ...) name
#define vec(type, name, ...) vector<type> name(__VA_ARGS__)
#define vv(type, name, h, ...) vector<vector<type>> name(h, vector<type>(__VA_ARGS__))
#define vvv(type, name, h, w, ...) vector<vector<vector<type>>> name(h, vector<vector<type>>(w, vector<type>(__VA_ARGS__)))
#define vvvv(type, name, a, b, c, ...)                                                                                                                         \
    vector<vector<vector<vector<type>>>> name(a, vector<vector<vector<type>>>(b, vector<vector<type>>(c, vector<type>(__VA_ARGS__))))
constexpr pii dx4[4] = {pii{1, 0}, pii{0, 1}, pii{-1, 0}, pii{0, -1}};
constexpr pii dx8[8] = {{1, 0}, {1, 1}, {0, 1}, {-1, 1}, {-1, 0}, {-1, -1}, {0, -1}, {1, -1}};

namespace yesno_impl {
const string YESNO[2] = {"NO", "YES"};
const string YesNo[2] = {"No", "Yes"};
const string yesno[2] = {"no", "yes"};
const string firstsecond[2] = {"second", "first"};
const string FirstSecond[2] = {"Second", "First"};
const string possiblestr[2] = {"impossible", "possible"};
void YES(bool t = 1) { cout << YESNO[t] << endl; }
void NO(bool t = 1) { YES(!t); }
void Yes(bool t = 1) { cout << YesNo[t] << endl; }
void No(bool t = 1) { Yes(!t); }
void yes(bool t = 1) { cout << yesno[t] << endl; }
void no(bool t = 1) { yes(!t); }
void first(bool t = 1) { cout << firstsecond[t] << endl; }
void First(bool t = 1) { cout << FirstSecond[t] << endl; }
void possible(bool t = 1) { cout << possiblestr[t] << endl; }
}; // namespace yesno_impl
using namespace yesno_impl;

#define INT(...)                                                                                                                                               \
    int __VA_ARGS__;                                                                                                                                           \
    IN(__VA_ARGS__)
#define LL(...)                                                                                                                                                \
    ll __VA_ARGS__;                                                                                                                                            \
    IN(__VA_ARGS__)
#define STR(...)                                                                                                                                               \
    string __VA_ARGS__;                                                                                                                                        \
    IN(__VA_ARGS__)
#define CHR(...)                                                                                                                                               \
    char __VA_ARGS__;                                                                                                                                          \
    IN(__VA_ARGS__)
#define DBL(...)                                                                                                                                               \
    double __VA_ARGS__;                                                                                                                                        \
    IN(__VA_ARGS__)
#define VEC(type, name, size)                                                                                                                                  \
    vector<type> name(size);                                                                                                                                   \
    IN(name)
#define VEC2(type, name1, name2, size)                                                                                                                         \
    vector<type> name1(size), name2(size);                                                                                                                     \
    for(int i = 0; i < size; i++) IN(name1[i], name2[i])
#define VEC3(type, name1, name2, name3, size)                                                                                                                  \
    vector<type> name1(size), name2(size), name3(size);                                                                                                        \
    for(int i = 0; i < size; i++) IN(name1[i], name2[i], name3[i])
#define VEC4(type, name1, name2, name3, name4, size)                                                                                                           \
    vector<type> name1(size), name2(size), name3(size), name4(size);                                                                                           \
    for(int i = 0; i < size; i++) IN(name1[i], name2[i], name3[i], name4[i]);
#define VV(type, name, h, w)                                                                                                                                   \
    vector<vector<type>> name(h, vector<type>(w));                                                                                                             \
    IN(name)
int scan() { return getchar(); }
void scan(int &a) { cin >> a; }
void scan(long long &a) { cin >> a; }
void scan(char &a) { cin >> a; }
void scan(double &a) { cin >> a; }
void scan(string &a) { cin >> a; }
template <class T, class S> void scan(pair<T, S> &p) { scan(p.first), scan(p.second); }
template <class T> void scan(vector<T> &);
template <class T> void scan(vector<T> &a) {
    for(auto &i : a) scan(i);
}
template <class T> void scan(T &a) { cin >> a; }
void IN() {}
template <class Head, class... Tail> void IN(Head &head, Tail &...tail) {
    scan(head);
    IN(tail...);
}

template <typename T, typename S> T ceil(T x, S y) {
    assert(y);
    return (y < 0 ? ceil(-x, -y) : (x > 0 ? (x + y - 1) / y : x / y));
}

template <typename T, typename S> T floor(T x, S y) {
    assert(y);
    return (y < 0 ? floor(-x, -y) : (x > 0 ? x / y : x / y - (x % y == 0 ? 0 : 1)));
}
template <class T> T POW(T x, int n) {
    T res = 1;
    for(; n; n >>= 1, x *= x)
        if(n & 1) res *= x;
    return res;
}
template <class T, class S> T POW(T x, S n, const ll &mod) {
    T res = 1;
    x %= mod;
    for(; n; n >>= 1, x = x * x % mod)
        if(n & 1) res = res * x % mod;
    return res;
}
vector<pll> factor(ll x) {
    vector<pll> ans;
    for(ll i = 2; i * i <= x; i++)
        if(x % i == 0) {
            ans.push_back({i, 1});
            while((x /= i) % i == 0) ans.back().second++;
        }
    if(x != 1) ans.push_back({x, 1});
    return ans;
}
template <class T> vector<T> divisor(T x) {
    vector<T> ans;
    for(T i = 1; i * i <= x; i++)
        if(x % i == 0) {
            ans.pb(i);
            if(i * i != x) ans.pb(x / i);
        }
    return ans;
}
template <typename T> void zip(vector<T> &x) {
    vector<T> y = x;
    UNIQUE(y);
    for(int i = 0; i < x.size(); ++i) { x[i] = lb(y, x[i]); }
}
template <class S> void fold_in(vector<S> &v) {}
template <typename Head, typename... Tail, class S> void fold_in(vector<S> &v, Head &&a, Tail &&...tail) {
    for(auto e : a) v.emplace_back(e);
    fold_in(v, tail...);
}
template <class S> void renumber(vector<S> &v) {}
template <typename Head, typename... Tail, class S> void renumber(vector<S> &v, Head &&a, Tail &&...tail) {
    for(auto &&e : a) e = lb(v, e);
    renumber(v, tail...);
}
template <class S, class... Args> vector<S> zip(vector<S> &head, Args &&...args) {
    vector<S> v;
    fold_in(v, head, args...);
    sort(all(v)), v.erase(unique(all(v)), v.end());
    renumber(v, head, args...);
    return v;
}
template <typename T> vector<T> RUI(const vector<T> &v) {
    vector<T> res(v.size() + 1);
    for(int i = 0; i < v.size(); i++) res[i + 1] = res[i] + v[i];
    return res;
}
// 反時計周りに 90 度回転
template <typename T> void rot(vector<vector<T>> &v) {
    if(empty(v)) return;
    int n = v.size(), m = v[0].size();
    vector res(m, vector<T>(n));
    rep(i, n) rep(j, m) res[m - 1 - j][i] = v[i][j];
    v.swap(res);
}
// x in [l, r)
template <class T, class S> bool inc(const T &x, const S &l, const S &r) { return l <= x and x < r; }

// 便利関数
constexpr ll ten(int n) { return n == 0 ? 1 : ten(n - 1) * 10; }
constexpr ll tri(ll n) { return n * (n + 1) / 2; }
// l + ... + r
constexpr ll tri(ll l, ll r) { return (l + r) * (r - l + 1) / 2; }
ll max(int x, ll y) { return max((ll)x, y); }
ll max(ll x, int y) { return max(x, (ll)y); }
int min(int x, ll y) { return min((ll)x, y); }
int min(ll x, int y) { return min(x, (ll)y); }
// bit 演算系
ll pow2(int i) { return 1LL << i; }
int topbit(signed t) { return t == 0 ? -1 : 31 - __builtin_clz(t); }
int topbit(ll t) { return t == 0 ? -1 : 63 - __builtin_clzll(t); }
int lowbit(signed a) { return a == 0 ? 32 : __builtin_ctz(a); }
int lowbit(ll a) { return a == 0 ? 64 : __builtin_ctzll(a); }
// int allbit(int n) { return (1 << n) - 1; }
constexpr ll mask(int n) { return (1LL << n) - 1; }
// int popcount(signed t) { return __builtin_popcount(t); }
// int popcount(ll t) { return __builtin_popcountll(t); }
int popcount(uint64_t t) { return __builtin_popcountll(t); }
static inline uint64_t popcount64(uint64_t x) {
    uint64_t m1 = 0x5555555555555555ll;
    uint64_t m2 = 0x3333333333333333ll;
    uint64_t m4 = 0x0F0F0F0F0F0F0F0Fll;
    uint64_t h01 = 0x0101010101010101ll;

    x -= (x >> 1) & m1;
    x = (x & m2) + ((x >> 2) & m2);
    x = (x + (x >> 4)) & m4;

    return (x * h01) >> 56;
}
bool ispow2(int i) { return i && (i & -i) == i; }

// ll rnd(ll l, ll r) { //[l, r)
// #ifdef noimi
//     static mt19937_64 gen;
// #else
//     static mt19937_64 gen(chrono::steady_clock::now().time_since_epoch().count());
// #endif
//     return uniform_int_distribution<ll>(l, r - 1)(gen);
// }
// ll rnd(ll n) { return rnd(0, n); }

// template <class t> void random_shuffle(vc<t> &a) { rep(i, si(a)) swap(a[i], a[rnd(0, i + 1)]); }

int in() {
    int x;
    cin >> x;
    return x;
}
ll lin() {
    unsigned long long x;
    cin >> x;
    return x;
}

template <class T, class S> pair<T, S> operator-(const pair<T, S> &x) { return pair<T, S>(-x.first, -x.second); }
template <class T, class S> pair<T, S> operator-(const pair<T, S> &x, const pair<T, S> &y) { return pair<T, S>(x.fi - y.fi, x.se - y.se); }
template <class T, class S> pair<T, S> operator+(const pair<T, S> &x, const pair<T, S> &y) { return pair<T, S>(x.fi + y.fi, x.se + y.se); }
template <class T> pair<T, T> operator&(const pair<T, T> &l, const pair<T, T> &r) { return pair<T, T>(max(l.fi, r.fi), min(l.se, r.se)); }
template <class T, class S> pair<T, S> operator+=(pair<T, S> &l, const pair<T, S> &r) { return l = l + r; }
template <class T, class S> pair<T, S> operator-=(pair<T, S> &l, const pair<T, S> &r) { return l = l - r; }
template <class T> bool intersect(const pair<T, T> &l, const pair<T, T> &r) { return (l.se < r.se ? r.fi < l.se : l.fi < r.se); }

template <typename T> struct edge {
    int from, to;
    T cost;
    int id;
    edge(int to, T cost) : from(-1), to(to), cost(cost) {}
    edge(int from, int to, T cost) : from(from), to(to), cost(cost) {}
    edge(int from, int to, T cost, int id) : from(from), to(to), cost(cost), id(id) {}
    constexpr bool operator<(const edge<T> &rhs) const noexcept { return cost < rhs.cost; }
    edge &operator=(const int &x) {
        to = x;
        return *this;
    }
    operator int() const { return to; }
    friend ostream operator<<(ostream &os, edge &e) { return os << e.to; }
};
template <typename T> using Edges = vector<edge<T>>;

using Tree = vector<vector<int>>;
using Graph = vector<vector<int>>;
template <class T> using Wgraph = vector<vector<edge<T>>>;
Graph getG(int n, int m = -1, bool directed = false, int margin = 1) {
    Tree res(n);
    if(m == -1) m = n - 1;
    while(m--) {
        int a, b;
        cin >> a >> b;
        a -= margin, b -= margin;
        res[a].emplace_back(b);
        if(!directed) res[b].emplace_back(a);
    }
    return res;
}
Graph getTreeFromPar(int n, int margin = 1) {
    Graph res(n);
    for(int i = 1; i < n; i++) {
        int a;
        cin >> a;
        res[a - margin].emplace_back(i);
    }
    return res;
}
template <class T> Wgraph<T> getWg(int n, int m = -1, bool directed = false, int margin = 1) {
    Wgraph<T> res(n);
    if(m == -1) m = n - 1;
    while(m--) {
        int a, b;
        T c;
        scan(a), scan(b), scan(c);
        a -= margin, b -= margin;
        res[a].emplace_back(b, c);
        if(!directed) res[b].emplace_back(a, c);
    }
    return res;
}
void add(Graph &G, int x, int y) { G[x].eb(y), G[y].eb(x); }
template <class S, class T> void add(Wgraph<S> &G, int x, int y, T c) { G[x].eb(y, c), G[y].eb(x, c); }

#define TEST                                                                                                                                                   \
    INT(testcases);                                                                                                                                            \
    while(testcases--)

istream &operator>>(istream &is, i128 &v) {
    string s;
    is >> s;
    v = 0;
    for(int i = 0; i < (int)s.size(); i++) {
        if(isdigit(s[i])) { v = v * 10 + s[i] - '0'; }
    }
    if(s[0] == '-') { v *= -1; }
    return is;
}

ostream &operator<<(ostream &os, const i128 &v) {
    if(v == 0) { return (os << "0"); }
    i128 num = v;
    if(v < 0) {
        os << '-';
        num = -num;
    }
    string s;
    for(; num > 0; num /= 10) { s.push_back((char)(num % 10) + '0'); }
    reverse(s.begin(), s.end());
    return (os << s);
}
namespace aux {
template <typename T, unsigned N, unsigned L> struct tp {
    static void output(std::ostream &os, const T &v) {
        os << std::get<N>(v) << (&os == &cerr ? ", " : " ");
        tp<T, N + 1, L>::output(os, v);
    }
};
template <typename T, unsigned N> struct tp<T, N, N> {
    static void output(std::ostream &os, const T &v) { os << std::get<N>(v); }
};
} // namespace aux
template <typename... Ts> std::ostream &operator<<(std::ostream &os, const std::tuple<Ts...> &t) {
    if(&os == &cerr) { os << '('; }
    aux::tp<std::tuple<Ts...>, 0, sizeof...(Ts) - 1>::output(os, t);
    if(&os == &cerr) { os << ')'; }
    return os;
}
template <class T, class S> ostream &operator<<(ostream &os, const pair<T, S> &p) {
    if(&os == &cerr) { return os << "(" << p.first << ", " << p.second << ")"; }
    return os << p.first << " " << p.second;
}
template <class Ch, class Tr, class Container> std::basic_ostream<Ch, Tr> &operator<<(std::basic_ostream<Ch, Tr> &os, const Container &x) {
    bool f = true;
    if(&os == &cerr) os << "[";
    for(auto &y : x) {
        if(&os == &cerr)
            os << (f ? "" : ", ") << y;
        else
            os << (f ? "" : " ") << y;
        f = false;
    }
    if(&os == &cerr) os << "]";
    return os;
}

#ifdef noimi
#undef endl
void debug() { cerr << endl; }
void debug(bool) { cerr << endl; }
template <class Head, class... Tail> void debug(bool is_front, Head head, Tail... tail) {
    if(!is_front) cerr << ", ";
    cerr << head;
    debug(false, tail...);
}

#define dump(args...)                                                                                                                                          \
    {                                                                                                                                                          \
        vector<string> _debug = _split(#args, ',');                                                                                                            \
        err(true, begin(_debug), args);                                                                                                                        \
    }

vector<string> _split(const string &s, char c) {
    vector<string> v;
    stringstream ss(s);
    string x;
    while(getline(ss, x, c)) {
        if(empty(v))
            v.eb(x);
        else {
            bool flag = false;
            for(auto [c, d] : {pair('(', ')'), pair('[', ']'), pair('{', '}')}) {
                if(count(all(v.back()), c) != count(all(v.back()), d)) flag = true;
            }
            if(flag)
                v.back() += "," + x;
            else
                v.eb(x);
        }
    }
    return move(v);
}

void err(bool, vector<string>::iterator) { cerr << endl; }
template <typename T, typename... Args> void err(bool is_front, vector<string>::iterator it, T a, Args... args) {
    if(!is_front) cerr << ", ";
    cerr << it->substr((*it)[0] == ' ', (*it).size()) << " = " << a, err(false, ++it, args...);
}

// #define dump(...) cerr << #__VA_ARGS__ << " : ", debug(true, __VA_ARGS__)
#else
#define dump(...) static_cast<void>(0)
#define dbg(...) static_cast<void>(0)
#endif
void OUT() { cout << endl; }
template <class Head, class... Tail> void OUT(const Head &head, const Tail &...tail) {
    cout << head;
    if(sizeof...(tail)) cout << ' ';
    OUT(tail...);
}

template <typename T> static constexpr T inf = numeric_limits<T>::max() / 2;
template <class T, class S> constexpr pair<T, S> inf<pair<T, S>> = {inf<T>, inf<S>};

template <class F> struct REC {
    F f;
    REC(F &&f_) : f(std::forward<F>(f_)) {}
    template <class... Args> auto operator()(Args &&...args) const { return f(*this, std::forward<Args>(args)...); }
};

template <class S> vector<pair<S, int>> runLength(const vector<S> &v) {
    vector<pair<S, int>> res;
    for(auto &e : v) {
        if(res.empty() or res.back().fi != e)
            res.eb(e, 1);
        else
            res.back().se++;
    }
    return res;
}
vector<pair<char, int>> runLength(const string &v) {
    vector<pair<char, int>> res;
    for(auto &e : v) {
        if(res.empty() or res.back().fi != e)
            res.eb(e, 1);
        else
            res.back().se++;
    }
    return res;
}

int toint(const char &c, const char start = 'a') { return c - start; }
int toint(const char &c, const string &chars) { return find(all(chars), c) - begin(chars); }
int alphabets_to_int(const char &c) { return (islower(c) ? c - 'a' : c - 'A' + 26); }
template <typename T> auto toint(const T &v, const char &start = 'a') {
    vector<decltype(toint(v[0]))> ret;
    ret.reserve(v.size());
    for(auto &&e : v) ret.emplace_back(toint(e, start));
    return ret;
}
template <typename T> auto toint(const T &v, const string &start) {
    vector<decltype(toint(v[0]))> ret;
    ret.reserve(v.size());
    for(auto &&e : v) ret.emplace_back(toint(e, start));
    return ret;
}
// a -> 0, A -> 26
template <typename T> auto alphabets_to_int(const T &s) {
    vector<decltype(alphabets_to_int(s[0]))> res;
    res.reserve(s.size());
    for(auto &&e : s) { res.emplace_back(alphabets_to_int(e)); }
    return res;
}

template <class T, class F> T bin_search(T ok, T ng, const F &f) {
    while(abs(ok - ng) > 1) {
        T mid = ok + ng >> 1;
        (f(mid) ? ok : ng) = mid;
    }
    return ok;
}
template <class T, class F> T bin_search_double(T ok, T ng, const F &f, int iter = 80) {
    while(iter--) {
        T mid = (ok + ng) / 2;
        (f(mid) ? ok : ng) = mid;
    }
    return ok;
}

struct Setup_io {
    Setup_io() {
        ios_base::sync_with_stdio(0), cin.tie(0), cout.tie(0);
        cout << fixed << setprecision(11);
    }
} setup_io;

#pragma endregion

int main() {
    while(true) {
        INT(n, m, s, t);
        if(!n) exit(0);
        s--, t--;
        using B = bitset<200>;

        vv(int, d, n, n);
        vector<B> D(n);
        queue<pii> q;
        vector<B> x(n);
        vector<B> y(n);
        Wgraph<char> g(n), rg(n);
        rep(i, m) {
            INT(u, v);
            u--, v--;
            CHR(c);
            if(c == 'a' and !d[u][v]) {
                d[u][v] = D[v][u] = 1, q.emplace(u, v);
                g[u].eb(v, c);
            } else if(c == '(')
                x[v][u] = 1;
            else if(c == '[')
                y[v][u] = 1;
            else
                g[u].eb(v, c);
            if(c == '+' or c == '*') rg[v].eb(u, c);
        }
        while(!empty(q)) {
            auto [u, v] = q.front();
            q.pop();
            // dump(u, v);
            fore(e, g[v]) {
                if(e.cost == '+' or e.cost == '*') {
                    rep(s, n) {
                        if(d[e][s] and !d[u][s]) d[u][s] = D[s][u] = true, q.emplace(u, s);
                    }
                } else if(e.cost == ')') {
                    auto b = ~D[e] & x[u];
                    // dump(b);
                    for(int i = b._Find_first(); i < si(b); i = b._Find_next(i)) {
                        // dump(i);
                        d[i][e] = D[e][i] = true, q.emplace(i, e);
                    }
                } else if(e.cost == ']') {
                    auto b = ~D[e] & y[u];
                    for(int i = b._Find_first(); i < si(b); i = b._Find_next(i)) { d[i][e] = D[e][i] = true, q.emplace(i, e); }
                }
            }

            fore(e, rg[u]) {
                if(e.cost == '+' or e.cost == '*') {
                    // dump(e.to, u, v);
                    rep(s, n) {
                        if(d[s][e] and !d[s][v]) d[s][v] = D[v][s] = true, q.emplace(s, v);
                    }
                }
            }
        }
        Yes(d[s][t]);
    }
}
accuracy: 1
time_ms: 6070
memory_kb: 6180
final_rank: 18

code_snippet: #pragma GCC optimize("Ofast,no-stack-protector,unroll-loops,fast-math")
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define pb(...) emplace_back(__VA_ARGS__)
#define mp(a, b) make_pair(a, b)
#define all(x) x.begin(), x.end()
#define rall(x) x.rbegin(), x.rend()
#define rep(i, n) for (int i = 0; i < (n); i++)
#define rep2(i, n) for (int i = (int)n - 1; i >= 0; i--)
#define REP(i, l, r) for (int i = l; i < (r); i++)
#define REP2(i, l, r) for (int i = (int)r - 1; i >= (l); i--)
#define siz(x) (ll) x.size()
template <class T>
using rque = priority_queue<T, vector<T>, greater<T>>;

template <class T>
bool chmin(T &a, const T &b) {
    if (b < a) {
        a = b;
        return 1;
    }
    return 0;
}

template <class T>
bool chmax(T &a, const T &b) {
    if (b > a) {
        a = b;
        return 1;
    }
    return 0;
}

template <class T>
void print(vector<T> a) {
    if (a.empty())
        cout << '\n';
    else {
        for (int i = 0; i < a.size(); i++)
            cout << a[i] << (i + 1 == a.size() ? '\n' : ' ');
    }
}

// __int128_t gcd(__int128_t a, __int128_t b) {
//     if (a == 0)
//         return b;
//     if (b == 0)
//         return a;
//     __int128_t cnt = a % b;
//     while (cnt != 0) {
//         a = b;
//         b = cnt;
//         cnt = a % b;
//     }
//     return b;
// }

long long extGCD(long long a, long long b, long long &x, long long &y) {
    if (b == 0) {
        x = 1;
        y = 0;
        return a;
    }
    long long d = extGCD(b, a % b, y, x);
    y -= a / b * x;
    return d;
}

struct UnionFind {
    vector<int> data;
    int num;

    UnionFind(int sz) {
        data.assign(sz, -1);
        num = sz;
    }

    bool unite(int x, int y) {
        x = find(x), y = find(y);
        if (x == y)
            return (false);
        if (data[x] > data[y])
            swap(x, y);
        data[x] += data[y];
        data[y] = x;
        num--;
        return (true);
    }

    int find(int k) {
        if (data[k] < 0)
            return (k);
        return (data[k] = find(data[k]));
    }

    int size(int k) {
        return (-data[find(k)]);
    }

    bool same(int x, int y) {
        return find(x) == find(y);
    }

    int operator[](int k) {
        return find(k);
    }
};

template <int mod>
struct Mod_Int {
    int x;

    Mod_Int() : x(0) {
    }

    Mod_Int(long long y) : x(y >= 0 ? y % mod : (mod - (-y) % mod) % mod) {
    }

    static int get_mod() {
        return mod;
    }

    Mod_Int &operator+=(const Mod_Int &p) {
        if ((x += p.x) >= mod)
            x -= mod;
        return *this;
    }

    Mod_Int &operator-=(const Mod_Int &p) {
        if ((x += mod - p.x) >= mod)
            x -= mod;
        return *this;
    }

    Mod_Int &operator*=(const Mod_Int &p) {
        x = (int)(1LL * x * p.x % mod);
        return *this;
    }

    Mod_Int &operator/=(const Mod_Int &p) {
        *this *= p.inverse();
        return *this;
    }

    Mod_Int &operator++() {
        return *this += Mod_Int(1);
    }

    Mod_Int operator++(int) {
        Mod_Int tmp = *this;
        ++*this;
        return tmp;
    }

    Mod_Int &operator--() {
        return *this -= Mod_Int(1);
    }

    Mod_Int operator--(int) {
        Mod_Int tmp = *this;
        --*this;
        return tmp;
    }

    Mod_Int operator-() const {
        return Mod_Int(-x);
    }

    Mod_Int operator+(const Mod_Int &p) const {
        return Mod_Int(*this) += p;
    }

    Mod_Int operator-(const Mod_Int &p) const {
        return Mod_Int(*this) -= p;
    }

    Mod_Int operator*(const Mod_Int &p) const {
        return Mod_Int(*this) *= p;
    }

    Mod_Int operator/(const Mod_Int &p) const {
        return Mod_Int(*this) /= p;
    }

    bool operator==(const Mod_Int &p) const {
        return x == p.x;
    }

    bool operator!=(const Mod_Int &p) const {
        return x != p.x;
    }

    Mod_Int inverse() const {
        assert(*this != Mod_Int(0));
        return pow(mod - 2);
    }

    Mod_Int pow(long long k) const {
        Mod_Int now = *this, ret = 1;
        for (; k > 0; k >>= 1, now *= now) {
            if (k & 1)
                ret *= now;
        }
        return ret;
    }

    friend ostream &operator<<(ostream &os, const Mod_Int &p) {
        return os << p.x;
    }

    friend istream &operator>>(istream &is, Mod_Int &p) {
        long long a;
        is >> a;
        p = Mod_Int<mod>(a);
        return is;
    }
};

ll mpow2(ll x, ll n, ll mod) {
    ll ans = 1;
    x %= mod;
    while (n != 0) {
        if (n & 1)
            ans = ans * x % mod;
        x = x * x % mod;
        n = n >> 1;
    }
    ans %= mod;
    return ans;
}

ll modinv2(ll a, ll mod) {
    ll b = mod, u = 1, v = 0;
    while (b) {
        ll t = a / b;
        a -= t * b;
        swap(a, b);
        u -= t * v;
        swap(u, v);
    }
    u %= mod;
    if (u < 0)
        u += mod;
    return u;
}

ll divide_int(ll a, ll b) {
    return (a >= 0 ? a / b : (a - b + 1) / b);
}

constexpr int mod = 1000000007;
// constexpr int mod = 998244353;
// constexpr int mod = 31607;
using mint = Mod_Int<mod>;

mint mpow(mint x, ll n) {
    bool rev = n < 0;
    n = abs(n);
    mint ans = 1;
    while (n != 0) {
        if (n & 1)
            ans *= x;
        x *= x;
        n = n >> 1;
    }
    return (rev ? ans.inverse() : ans);
}

// ----- library -------
// ----- library -------

int main() {
    ios::sync_with_stdio(false);
    std::cin.tie(nullptr);
    cout << fixed << setprecision(15);

    while (1) {
        int n, m, s, t;
        cin >> n >> m >> s >> t;
        if (!n)
            break;
        s--, t--;
        vector<vector<pair<pair<int, char>, int>>> li(n), ri(n);
        int a, b;
        char c;
        rep(i, m) cin >> a >> b >> c, a--, b--, li[a].pb(mp(b, c), i), ri[b].pb(mp(a, c), i);
        vector f(n, vector(n, vector(3, vector(5, 0))));
        vector<set<int>> lsp(n), rsp(n), lsc(n), rsc(n);
        queue<pair<pair<int, int>, pair<int, int>>> que;
        rep(i, n) {
            for (auto [info, id] : li[i]) {
                auto [dst, nc] = info;
                if (nc == 'a')
                    que.push({{i, dst}, {0, 0}}), f[i][dst][0][0] = 1;
            }
        }
        while (!que.empty()) {
            auto [nij, nkl] = que.front();
            que.pop();
            auto [ni, nj] = nij;
            auto [nk, nl] = nkl;
            if (nk < 2) {
                if(!f[ni][nj][nk + 1][nl])
                    que.push({{ni, nj}, {nk + 1, nl}}), f[ni][nj][nk + 1][nl] = 1;
            }
            if (!nl) {
                if (nk == 0) {
                    for (auto e : rsc[ni]) {
                        if(!f[e][nj][1][0])
                            que.push({{e, nj}, {1, 0}}), f[e][nj][1][0] = 1;
                    }
                    for (auto [info, id] : ri[ni]) {
                        auto [dst, nc] = info;
                        if (nc == '*')
                            lsc[dst].insert(nj);
                    }
                }
                if (nk == 1) {
                    for (auto e : lsc[nj]) {
                        if(!f[ni][e][1][0])
                            que.push({{ni, e}, {1, 0}}), f[ni][e][1][0] = 1;
                    }
                    for (auto [info, id] : li[nj]) {
                        auto [dst, nc] = info;
                        if (nc == '*')
                            rsc[dst].insert(ni);
                    }
                    for (auto e : rsp[ni]) {
                        if(!f[e][nj][2][0])
                            que.push({{e, nj}, {2, 0}}), f[e][nj][2][0] = 1;
                    }
                    for (auto [info, id] : ri[ni]) {
                        auto [dst, nc] = info;
                        if (nc == '+')
                            lsp[dst].insert(nj);
                    }
                }
                if (nk == 2) {
                    for (auto e : lsp[nj]) {
                        if(!f[ni][e][2][0])
                            que.push({{ni, e}, {2, 0}}), f[ni][e][2][0] = 1;
                    }
                    for (auto [info, id] : li[nj]) {
                        auto [dst, nc] = info;
                        if (nc == '+')
                            rsp[dst].insert(ni);
                    }
                }
            }
            if (nl < 3 && !(nl & 1)) {
                int nel = nl | 1;
                if (nel == 3)
                    nel = 0;
                for (auto [info, id] : ri[ni]) {
                    auto [dst, nc] = info;
                    if (nc == '(') {
                        if(!f[dst][nj][0][nel])
                            que.push({{dst, nj}, {0, nel}}), f[dst][nj][0][nel] = 1;
                    }
                }
            }
            if (nl < 3 && !(nl & 2)) {
                int nel = nl | 2;
                if (nel == 3)
                    nel = 0;
                for (auto [info, id] : li[nj]) {
                    auto [dst, nc] = info;
                    if (nc == ')') {
                        if(!f[ni][dst][0][nel])
                            que.push({{ni, dst}, {0, nel}}), f[ni][dst][0][nel] = 1;
                    }
                }
            }
            if (!nl || nl >= 3) {
                int nel = nl;
                if (nl)
                    nel -= 2;
                if (!(nel & 1)) {
                    nel |= 1;
                    if (nel == 3)
                        nel = 0;
                    else
                        nel += 2;
                    for (auto [info, id] : ri[ni]) {
                        auto [dst, nc] = info;
                        if (nc == '[') {
                            if(!f[dst][nj][0][nel])
                                que.push({{dst, nj}, {0, nel}}), f[dst][nj][0][nel] = 1;
                        }
                    }
                }
                if (!(nel & 2)) {
                    nel |= 2;
                    if (nel == 3)
                        nel = 0;
                    else
                        nel += 2;
                    for (auto [info, id] : li[nj]) {
                        auto [dst, nc] = info;
                        if (nc == ']') {
                            if(!f[ni][dst][0][nel])
                                que.push({{ni, dst}, {0, nel}}), f[ni][dst][0][nel] = 1;
                        }
                    }
                }
            }
        }
        cout << (f[s][t][2][0] ? "Yes" : "No") << endl;
    }
}
accuracy: 1
time_ms: 4500
memory_kb: 23988
final_rank: 16

code_snippet: #pragma region template
#pragma GCC optimize("Ofast")
#include <bits/stdc++.h>
using namespace std;
#ifdef __LOCAL
 #include <debug>
#else
 #define debug(...) void(0)
#endif

#define REP(i,n) for(int i=0;i<(n);i++)
#define ALL(v) v.begin(),v.end()

template<typename T>
istream& operator>>(istream&is,vector<T>&v){
  for(T&p:v)is>>p;
  return is;
}
template<typename T>
ostream& operator<<(ostream&os,const vector<T>&v){
  if(&os==&cerr)os<<"[";
  for(int i=0;i<v.size();i++){
    os<<v[i];
    if(i+1<v.size())os<<(&os==&cerr?",":" ");
  }
  if(&os==&cerr)os<<"]";
  return os;
}
#pragma endregion template

template<typename T,typename ...Args>
auto make_vector(T x,int arg,Args ...args){
  if constexpr(sizeof...(args)==0)return vector<T>(arg,x);
  else return vector(arg,make_vector<T>(x,args...));
}

queue<tuple<int,int,int>> que;
bool check[200][200][3];
bool used[200][200][2];

void D(int u,int v,int id){
  if(check[u][v][id])return;
  debug(u,v,id);
  check[u][v][id]=true;
  que.emplace(u,v,id);
}

unordered_map<char,int> id1{ {'a',0}, {'+',1}, {'*',2}, {')',3}, {']',4} };
unordered_map<char,int> id2{ {'a',0}, {'+',1}, {'*',2}, {'(',3}, {'[',4} };

int main(){
  ios::sync_with_stdio(false);
  cin.tie(nullptr);

  int n,m,s,t;
  while(cin>>n>>m>>s>>t,n){
    s--;t--;

    auto g=make_vector< vector<int> >({},n,5);// a + * ) ]
    auto r=make_vector< vector<int> >({},n,5);// a + * ( [

    REP(_,m){
      int u,v;cin>>u>>v;u--;v--;
      char c;cin>>c;
      if(c!='(' and c!='[')g[u][id1[c]].push_back(v);
      if(c!=')' and c!=']')r[v][id2[c]].push_back(u);
    }
    
    memset(check,false,sizeof(check));
    memset(used,false,sizeof(used));

    REP(u,n)for(int v:g[u][0])D(u,v,2);

    while(que.size()){
      auto[u,v,id]=que.front();que.pop();
      if(id>=0 and !used[u][v][0]){
        used[u][v][0]=check[u][v][0]=true;
        for(int to:g[v][1])REP(i,n)if(check[to][i][1])D(u,i,0);
        for(int to:g[v][3])for(int to2:r[u][3])D(to2,to,2);
        for(int to:g[v][4])for(int to2:r[u][4])D(to2,to,2);
      }
      if(id>=1 and !used[u][v][1]){
        used[u][v][1]=check[u][v][1]=true;
        for(int to:g[v][2])REP(i,n)if(check[to][i][2])D(u,i,1);
        for(int to:r[u][1])REP(i,n)if(check[i][to][0])D(i,v,1);
      }
      if(id==2)
        for(int to:r[u][2])REP(i,n)if(check[i][to][1])D(i,v,1);
      if(check[s][t][0])while(que.size())que.pop();
    }

    if(check[s][t][0])cout<<"Yes\n";
    else cout<<"No\n";
  }
}
accuracy: 1
time_ms: 660
memory_kb: 5524
final_rank: 9

code_snippet: #pragma region Macros
#if defined(noimi) && defined(_GLIBCXX_DEBUG) && defined(_GLIBCXX_DEBUG_PEDANTIC)
// #pragma comment(linker, "/stack:200000000")
#include <stdc++.h>
#pragma GCC optimize("O3")
#else
#pragma GCC optimize("Ofast")
// #pragma GCC optimize("unroll-loops")
// #pragma GCC target("popcnt")
// #pragma GCC target("sse,sse2,sse3,ssse3,sse4,popcnt,fma,abm,mmx,avx,avx2,tune=native")
// #pragma GCC target("sse,sse2,sse3,ssse3,sse4,popcnt,fma,abm,mmx,avx,avx2")
// #pragma GCC target("avx2")
#include <bits/stdc++.h>
#endif

#ifdef noimi
#define oj_local(a, b) b
#else
#define oj_local(a, b) a
#endif

#define LOCAL if(oj_local(0, 1))
#define OJ if(oj_local(1, 0))

using namespace std;
using ll = long long;
using ull = unsigned long long int;
using i128 = __int128_t;
using pii = pair<int, int>;
using pll = pair<ll, ll>;
using ld = long double;
template <typename T> using vc = vector<T>;
template <typename T> using vvc = vector<vc<T>>;
template <typename T> using vvvc = vector<vvc<T>>;
using vi = vc<int>;
using vl = vc<ll>;
using vpi = vc<pii>;
using vpl = vc<pll>;
template <class T> using pq = priority_queue<T>;
template <class T> using pqg = priority_queue<T, vector<T>, greater<T>>;
template <typename T> int si(const T &x) { return x.size(); }
template <class T, class S> inline bool chmax(T &a, const S &b) { return (a < b ? a = b, 1 : 0); }
template <class T, class S> inline bool chmin(T &a, const S &b) { return (a > b ? a = b, 1 : 0); }
vi iota(int n) {
    vi a(n);
    return iota(a.begin(), a.end(), 0), a;
}
template <typename T> vi iota(const vector<T> &a, bool greater = false) {
    vi res(a.size());
    iota(res.begin(), res.end(), 0);
    sort(res.begin(), res.end(), [&](int i, int j) {
        if(greater) return a[i] > a[j];
        return a[i] < a[j];
    });
    return res;
}

// macros
#define overload5(a, b, c, d, e, name, ...) name
#define overload4(a, b, c, d, name, ...) name
#define endl '\n'
#define REP0(n) for(ll jidlsjf = 0; jidlsjf < n; ++jidlsjf)
#define REP1(i, n) for(ll i = 0; i < (n); ++i)
#define REP2(i, a, b) for(ll i = (a); i < (b); ++i)
#define REP3(i, a, b, c) for(ll i = (a); i < (b); i += (c))
#define rep(...) overload4(__VA_ARGS__, REP3, REP2, REP1, REP0)(__VA_ARGS__)
#define per0(n) for(int jidlsjf = 0; jidlsjf < (n); ++jidlsjf)
#define per1(i, n) for(ll i = (n)-1; i >= 0; --i)
#define per2(i, a, b) for(ll i = (a)-1; i >= b; --i)
#define per3(i, a, b, c) for(ll i = (a)-1; i >= (b); i -= (c))
#define per(...) overload4(__VA_ARGS__, per3, per2, per1, per0)(__VA_ARGS__)
#define fore0(a) rep(a.size())
#define fore1(i, a) for(auto &&i : a)
#define fore2(a, b, v) for(auto &&[a, b] : v)
#define fore3(a, b, c, v) for(auto &&[a, b, c] : v)
#define fore4(a, b, c, d, v) for(auto &&[a, b, c, d] : v)
#define fore(...) overload5(__VA_ARGS__, fore4, fore3, fore2, fore1, fore0)(__VA_ARGS__)
#define fi first
#define se second
#define pb push_back
#define ppb pop_back
#define ppf pop_front
#define eb emplace_back
#define drop(s) cout << #s << endl, exit(0)
#define si(c) (int)(c).size()
#define lb(c, x) distance((c).begin(), lower_bound(all(c), (x)))
#define ub(c, x) distance((c).begin(), upper_bound(all(c), (x)))
#define rng(v, l, r) v.begin() + l, v.begin() + r
#define all(c) begin(c), end(c)
#define rall(c) rbegin(c), rend(c)
#define SORT(v) sort(all(v))
#define REV(v) reverse(all(v))
#define UNIQUE(x) SORT(x), x.erase(unique(all(x)), x.end())
template <typename T = ll, typename S> T SUM(const S &v) { return accumulate(all(v), T(0)); }
#define MIN(v) *min_element(all(v))
#define MAX(v) *max_element(all(v))
#define overload2(_1, _2, name, ...) name
#define vec(type, name, ...) vector<type> name(__VA_ARGS__)
#define vv(type, name, h, ...) vector<vector<type>> name(h, vector<type>(__VA_ARGS__))
#define vvv(type, name, h, w, ...) vector<vector<vector<type>>> name(h, vector<vector<type>>(w, vector<type>(__VA_ARGS__)))
#define vvvv(type, name, a, b, c, ...)                                                                                                                         \
    vector<vector<vector<vector<type>>>> name(a, vector<vector<vector<type>>>(b, vector<vector<type>>(c, vector<type>(__VA_ARGS__))))
constexpr pii dx4[4] = {pii{1, 0}, pii{0, 1}, pii{-1, 0}, pii{0, -1}};
constexpr pii dx8[8] = {{1, 0}, {1, 1}, {0, 1}, {-1, 1}, {-1, 0}, {-1, -1}, {0, -1}, {1, -1}};

namespace yesno_impl {
const string YESNO[2] = {"NO", "YES"};
const string YesNo[2] = {"No", "Yes"};
const string yesno[2] = {"no", "yes"};
const string firstsecond[2] = {"second", "first"};
const string FirstSecond[2] = {"Second", "First"};
const string possiblestr[2] = {"impossible", "possible"};
void YES(bool t = 1) { cout << YESNO[t] << endl; }
void NO(bool t = 1) { YES(!t); }
void Yes(bool t = 1) { cout << YesNo[t] << endl; }
void No(bool t = 1) { Yes(!t); }
void yes(bool t = 1) { cout << yesno[t] << endl; }
void no(bool t = 1) { yes(!t); }
void first(bool t = 1) { cout << firstsecond[t] << endl; }
void First(bool t = 1) { cout << FirstSecond[t] << endl; }
void possible(bool t = 1) { cout << possiblestr[t] << endl; }
}; // namespace yesno_impl
using namespace yesno_impl;

#define INT(...)                                                                                                                                               \
    int __VA_ARGS__;                                                                                                                                           \
    IN(__VA_ARGS__)
#define LL(...)                                                                                                                                                \
    ll __VA_ARGS__;                                                                                                                                            \
    IN(__VA_ARGS__)
#define STR(...)                                                                                                                                               \
    string __VA_ARGS__;                                                                                                                                        \
    IN(__VA_ARGS__)
#define CHR(...)                                                                                                                                               \
    char __VA_ARGS__;                                                                                                                                          \
    IN(__VA_ARGS__)
#define DBL(...)                                                                                                                                               \
    double __VA_ARGS__;                                                                                                                                        \
    IN(__VA_ARGS__)
#define VEC(type, name, size)                                                                                                                                  \
    vector<type> name(size);                                                                                                                                   \
    IN(name)
#define VEC2(type, name1, name2, size)                                                                                                                         \
    vector<type> name1(size), name2(size);                                                                                                                     \
    for(int i = 0; i < size; i++) IN(name1[i], name2[i])
#define VEC3(type, name1, name2, name3, size)                                                                                                                  \
    vector<type> name1(size), name2(size), name3(size);                                                                                                        \
    for(int i = 0; i < size; i++) IN(name1[i], name2[i], name3[i])
#define VEC4(type, name1, name2, name3, name4, size)                                                                                                           \
    vector<type> name1(size), name2(size), name3(size), name4(size);                                                                                           \
    for(int i = 0; i < size; i++) IN(name1[i], name2[i], name3[i], name4[i]);
#define VV(type, name, h, w)                                                                                                                                   \
    vector<vector<type>> name(h, vector<type>(w));                                                                                                             \
    IN(name)
int scan() { return getchar(); }
void scan(int &a) { cin >> a; }
void scan(long long &a) { cin >> a; }
void scan(char &a) { cin >> a; }
void scan(double &a) { cin >> a; }
void scan(string &a) { cin >> a; }
template <class T, class S> void scan(pair<T, S> &p) { scan(p.first), scan(p.second); }
template <class T> void scan(vector<T> &);
template <class T> void scan(vector<T> &a) {
    for(auto &i : a) scan(i);
}
template <class T> void scan(T &a) { cin >> a; }
void IN() {}
template <class Head, class... Tail> void IN(Head &head, Tail &...tail) {
    scan(head);
    IN(tail...);
}

template <typename T, typename S> T ceil(T x, S y) {
    assert(y);
    return (y < 0 ? ceil(-x, -y) : (x > 0 ? (x + y - 1) / y : x / y));
}

template <typename T, typename S> T floor(T x, S y) {
    assert(y);
    return (y < 0 ? floor(-x, -y) : (x > 0 ? x / y : x / y - (x % y == 0 ? 0 : 1)));
}
template <class T> T POW(T x, int n) {
    T res = 1;
    for(; n; n >>= 1, x *= x)
        if(n & 1) res *= x;
    return res;
}
template <class T, class S> T POW(T x, S n, const ll &mod) {
    T res = 1;
    x %= mod;
    for(; n; n >>= 1, x = x * x % mod)
        if(n & 1) res = res * x % mod;
    return res;
}
vector<pll> factor(ll x) {
    vector<pll> ans;
    for(ll i = 2; i * i <= x; i++)
        if(x % i == 0) {
            ans.push_back({i, 1});
            while((x /= i) % i == 0) ans.back().second++;
        }
    if(x != 1) ans.push_back({x, 1});
    return ans;
}
template <class T> vector<T> divisor(T x) {
    vector<T> ans;
    for(T i = 1; i * i <= x; i++)
        if(x % i == 0) {
            ans.pb(i);
            if(i * i != x) ans.pb(x / i);
        }
    return ans;
}
template <typename T> void zip(vector<T> &x) {
    vector<T> y = x;
    UNIQUE(y);
    for(int i = 0; i < x.size(); ++i) { x[i] = lb(y, x[i]); }
}
template <class S> void fold_in(vector<S> &v) {}
template <typename Head, typename... Tail, class S> void fold_in(vector<S> &v, Head &&a, Tail &&...tail) {
    for(auto e : a) v.emplace_back(e);
    fold_in(v, tail...);
}
template <class S> void renumber(vector<S> &v) {}
template <typename Head, typename... Tail, class S> void renumber(vector<S> &v, Head &&a, Tail &&...tail) {
    for(auto &&e : a) e = lb(v, e);
    renumber(v, tail...);
}
template <class S, class... Args> vector<S> zip(vector<S> &head, Args &&...args) {
    vector<S> v;
    fold_in(v, head, args...);
    sort(all(v)), v.erase(unique(all(v)), v.end());
    renumber(v, head, args...);
    return v;
}
template <typename T> vector<T> RUI(const vector<T> &v) {
    vector<T> res(v.size() + 1);
    for(int i = 0; i < v.size(); i++) res[i + 1] = res[i] + v[i];
    return res;
}
// 反時計周りに 90 度回転
template <typename T> void rot(vector<vector<T>> &v) {
    if(empty(v)) return;
    int n = v.size(), m = v[0].size();
    vector res(m, vector<T>(n));
    rep(i, n) rep(j, m) res[m - 1 - j][i] = v[i][j];
    v.swap(res);
}
// x in [l, r)
template <class T, class S> bool inc(const T &x, const S &l, const S &r) { return l <= x and x < r; }

// 便利関数
constexpr ll ten(int n) { return n == 0 ? 1 : ten(n - 1) * 10; }
constexpr ll tri(ll n) { return n * (n + 1) / 2; }
// l + ... + r
constexpr ll tri(ll l, ll r) { return (l + r) * (r - l + 1) / 2; }
ll max(int x, ll y) { return max((ll)x, y); }
ll max(ll x, int y) { return max(x, (ll)y); }
int min(int x, ll y) { return min((ll)x, y); }
int min(ll x, int y) { return min(x, (ll)y); }
// bit 演算系
ll pow2(int i) { return 1LL << i; }
int topbit(signed t) { return t == 0 ? -1 : 31 - __builtin_clz(t); }
int topbit(ll t) { return t == 0 ? -1 : 63 - __builtin_clzll(t); }
int lowbit(signed a) { return a == 0 ? 32 : __builtin_ctz(a); }
int lowbit(ll a) { return a == 0 ? 64 : __builtin_ctzll(a); }
// int allbit(int n) { return (1 << n) - 1; }
constexpr ll mask(int n) { return (1LL << n) - 1; }
// int popcount(signed t) { return __builtin_popcount(t); }
// int popcount(ll t) { return __builtin_popcountll(t); }
int popcount(uint64_t t) { return __builtin_popcountll(t); }
static inline uint64_t popcount64(uint64_t x) {
    uint64_t m1 = 0x5555555555555555ll;
    uint64_t m2 = 0x3333333333333333ll;
    uint64_t m4 = 0x0F0F0F0F0F0F0F0Fll;
    uint64_t h01 = 0x0101010101010101ll;

    x -= (x >> 1) & m1;
    x = (x & m2) + ((x >> 2) & m2);
    x = (x + (x >> 4)) & m4;

    return (x * h01) >> 56;
}
bool ispow2(int i) { return i && (i & -i) == i; }

// ll rnd(ll l, ll r) { //[l, r)
// #ifdef noimi
//     static mt19937_64 gen;
// #else
//     static mt19937_64 gen(chrono::steady_clock::now().time_since_epoch().count());
// #endif
//     return uniform_int_distribution<ll>(l, r - 1)(gen);
// }
// ll rnd(ll n) { return rnd(0, n); }

// template <class t> void random_shuffle(vc<t> &a) { rep(i, si(a)) swap(a[i], a[rnd(0, i + 1)]); }

int in() {
    int x;
    cin >> x;
    return x;
}
ll lin() {
    unsigned long long x;
    cin >> x;
    return x;
}

template <class T, class S> pair<T, S> operator-(const pair<T, S> &x) { return pair<T, S>(-x.first, -x.second); }
template <class T, class S> pair<T, S> operator-(const pair<T, S> &x, const pair<T, S> &y) { return pair<T, S>(x.fi - y.fi, x.se - y.se); }
template <class T, class S> pair<T, S> operator+(const pair<T, S> &x, const pair<T, S> &y) { return pair<T, S>(x.fi + y.fi, x.se + y.se); }
template <class T> pair<T, T> operator&(const pair<T, T> &l, const pair<T, T> &r) { return pair<T, T>(max(l.fi, r.fi), min(l.se, r.se)); }
template <class T, class S> pair<T, S> operator+=(pair<T, S> &l, const pair<T, S> &r) { return l = l + r; }
template <class T, class S> pair<T, S> operator-=(pair<T, S> &l, const pair<T, S> &r) { return l = l - r; }
template <class T> bool intersect(const pair<T, T> &l, const pair<T, T> &r) { return (l.se < r.se ? r.fi < l.se : l.fi < r.se); }

template <typename T> struct edge {
    int from, to;
    T cost;
    int id;
    edge(int to, T cost) : from(-1), to(to), cost(cost) {}
    edge(int from, int to, T cost) : from(from), to(to), cost(cost) {}
    edge(int from, int to, T cost, int id) : from(from), to(to), cost(cost), id(id) {}
    constexpr bool operator<(const edge<T> &rhs) const noexcept { return cost < rhs.cost; }
    edge &operator=(const int &x) {
        to = x;
        return *this;
    }
    operator int() const { return to; }
    friend ostream operator<<(ostream &os, edge &e) { return os << e.to; }
};
template <typename T> using Edges = vector<edge<T>>;

using Tree = vector<vector<int>>;
using Graph = vector<vector<int>>;
template <class T> using Wgraph = vector<vector<edge<T>>>;
Graph getG(int n, int m = -1, bool directed = false, int margin = 1) {
    Tree res(n);
    if(m == -1) m = n - 1;
    while(m--) {
        int a, b;
        cin >> a >> b;
        a -= margin, b -= margin;
        res[a].emplace_back(b);
        if(!directed) res[b].emplace_back(a);
    }
    return res;
}
Graph getTreeFromPar(int n, int margin = 1) {
    Graph res(n);
    for(int i = 1; i < n; i++) {
        int a;
        cin >> a;
        res[a - margin].emplace_back(i);
    }
    return res;
}
template <class T> Wgraph<T> getWg(int n, int m = -1, bool directed = false, int margin = 1) {
    Wgraph<T> res(n);
    if(m == -1) m = n - 1;
    while(m--) {
        int a, b;
        T c;
        scan(a), scan(b), scan(c);
        a -= margin, b -= margin;
        res[a].emplace_back(b, c);
        if(!directed) res[b].emplace_back(a, c);
    }
    return res;
}
void add(Graph &G, int x, int y) { G[x].eb(y), G[y].eb(x); }
template <class S, class T> void add(Wgraph<S> &G, int x, int y, T c) { G[x].eb(y, c), G[y].eb(x, c); }

#define TEST                                                                                                                                                   \
    INT(testcases);                                                                                                                                            \
    while(testcases--)

istream &operator>>(istream &is, i128 &v) {
    string s;
    is >> s;
    v = 0;
    for(int i = 0; i < (int)s.size(); i++) {
        if(isdigit(s[i])) { v = v * 10 + s[i] - '0'; }
    }
    if(s[0] == '-') { v *= -1; }
    return is;
}

ostream &operator<<(ostream &os, const i128 &v) {
    if(v == 0) { return (os << "0"); }
    i128 num = v;
    if(v < 0) {
        os << '-';
        num = -num;
    }
    string s;
    for(; num > 0; num /= 10) { s.push_back((char)(num % 10) + '0'); }
    reverse(s.begin(), s.end());
    return (os << s);
}
namespace aux {
template <typename T, unsigned N, unsigned L> struct tp {
    static void output(std::ostream &os, const T &v) {
        os << std::get<N>(v) << (&os == &cerr ? ", " : " ");
        tp<T, N + 1, L>::output(os, v);
    }
};
template <typename T, unsigned N> struct tp<T, N, N> {
    static void output(std::ostream &os, const T &v) { os << std::get<N>(v); }
};
} // namespace aux
template <typename... Ts> std::ostream &operator<<(std::ostream &os, const std::tuple<Ts...> &t) {
    if(&os == &cerr) { os << '('; }
    aux::tp<std::tuple<Ts...>, 0, sizeof...(Ts) - 1>::output(os, t);
    if(&os == &cerr) { os << ')'; }
    return os;
}
template <class T, class S> ostream &operator<<(ostream &os, const pair<T, S> &p) {
    if(&os == &cerr) { return os << "(" << p.first << ", " << p.second << ")"; }
    return os << p.first << " " << p.second;
}
template <class Ch, class Tr, class Container> std::basic_ostream<Ch, Tr> &operator<<(std::basic_ostream<Ch, Tr> &os, const Container &x) {
    bool f = true;
    if(&os == &cerr) os << "[";
    for(auto &y : x) {
        if(&os == &cerr)
            os << (f ? "" : ", ") << y;
        else
            os << (f ? "" : " ") << y;
        f = false;
    }
    if(&os == &cerr) os << "]";
    return os;
}

#ifdef noimi
#undef endl
void debug() { cerr << endl; }
void debug(bool) { cerr << endl; }
template <class Head, class... Tail> void debug(bool is_front, Head head, Tail... tail) {
    if(!is_front) cerr << ", ";
    cerr << head;
    debug(false, tail...);
}

#define dump(args...)                                                                                                                                          \
    {                                                                                                                                                          \
        vector<string> _debug = _split(#args, ',');                                                                                                            \
        err(true, begin(_debug), args);                                                                                                                        \
    }

vector<string> _split(const string &s, char c) {
    vector<string> v;
    stringstream ss(s);
    string x;
    while(getline(ss, x, c)) {
        if(empty(v))
            v.eb(x);
        else {
            bool flag = false;
            for(auto [c, d] : {pair('(', ')'), pair('[', ']'), pair('{', '}')}) {
                if(count(all(v.back()), c) != count(all(v.back()), d)) flag = true;
            }
            if(flag)
                v.back() += "," + x;
            else
                v.eb(x);
        }
    }
    return move(v);
}

void err(bool, vector<string>::iterator) { cerr << endl; }
template <typename T, typename... Args> void err(bool is_front, vector<string>::iterator it, T a, Args... args) {
    if(!is_front) cerr << ", ";
    cerr << it->substr((*it)[0] == ' ', (*it).size()) << " = " << a, err(false, ++it, args...);
}

// #define dump(...) cerr << #__VA_ARGS__ << " : ", debug(true, __VA_ARGS__)
#else
#define dump(...) static_cast<void>(0)
#define dbg(...) static_cast<void>(0)
#endif
void OUT() { cout << endl; }
template <class Head, class... Tail> void OUT(const Head &head, const Tail &...tail) {
    cout << head;
    if(sizeof...(tail)) cout << ' ';
    OUT(tail...);
}

template <typename T> static constexpr T inf = numeric_limits<T>::max() / 2;
template <class T, class S> constexpr pair<T, S> inf<pair<T, S>> = {inf<T>, inf<S>};

template <class F> struct REC {
    F f;
    REC(F &&f_) : f(std::forward<F>(f_)) {}
    template <class... Args> auto operator()(Args &&...args) const { return f(*this, std::forward<Args>(args)...); }
};

template <class S> vector<pair<S, int>> runLength(const vector<S> &v) {
    vector<pair<S, int>> res;
    for(auto &e : v) {
        if(res.empty() or res.back().fi != e)
            res.eb(e, 1);
        else
            res.back().se++;
    }
    return res;
}
vector<pair<char, int>> runLength(const string &v) {
    vector<pair<char, int>> res;
    for(auto &e : v) {
        if(res.empty() or res.back().fi != e)
            res.eb(e, 1);
        else
            res.back().se++;
    }
    return res;
}

int toint(const char &c, const char start = 'a') { return c - start; }
int toint(const char &c, const string &chars) { return find(all(chars), c) - begin(chars); }
int alphabets_to_int(const char &c) { return (islower(c) ? c - 'a' : c - 'A' + 26); }
template <typename T> auto toint(const T &v, const char &start = 'a') {
    vector<decltype(toint(v[0]))> ret;
    ret.reserve(v.size());
    for(auto &&e : v) ret.emplace_back(toint(e, start));
    return ret;
}
template <typename T> auto toint(const T &v, const string &start) {
    vector<decltype(toint(v[0]))> ret;
    ret.reserve(v.size());
    for(auto &&e : v) ret.emplace_back(toint(e, start));
    return ret;
}
// a -> 0, A -> 26
template <typename T> auto alphabets_to_int(const T &s) {
    vector<decltype(alphabets_to_int(s[0]))> res;
    res.reserve(s.size());
    for(auto &&e : s) { res.emplace_back(alphabets_to_int(e)); }
    return res;
}

template <class T, class F> T bin_search(T ok, T ng, const F &f) {
    while(abs(ok - ng) > 1) {
        T mid = ok + ng >> 1;
        (f(mid) ? ok : ng) = mid;
    }
    return ok;
}
template <class T, class F> T bin_search_double(T ok, T ng, const F &f, int iter = 80) {
    while(iter--) {
        T mid = (ok + ng) / 2;
        (f(mid) ? ok : ng) = mid;
    }
    return ok;
}

struct Setup_io {
    Setup_io() {
        ios_base::sync_with_stdio(0), cin.tie(0), cout.tie(0);
        cout << fixed << setprecision(11);
    }
} setup_io;

#pragma endregion

int main() {
    while(true) {
        INT(n, m, s, t);
        if(!n) exit(0);
        s--, t--;
        using B = bitset<200>;

        vv(int, d, n, n);
        vector<B> D(n);
        queue<pii> q;
        vector<B> x(n);
        vector<B> y(n);
        Wgraph<char> g(n), rg(n);
        rep(i, m) {
            INT(u, v);
            u--, v--;
            CHR(c);
            if(c == 'a' and !d[u][v]) {
                d[u][v] = D[v][u] = 1, q.emplace(u, v);
                g[u].eb(v, c);
            } else if(c == '(')
                x[v][u] = 1;
            else if(c == '[')
                y[v][u] = 1;
            else
                g[u].eb(v, c);
            if(c == '+' or c == '*') rg[v].eb(u, c);
        }
        while(!empty(q)) {
            auto [u, v] = q.front();
            q.pop();
            // dump(u, v);
            fore(e, g[v]) {
                if(e.cost == '+' or e.cost == '*') {
                    rep(s, n) {
                        if(d[e][s] and !d[u][s]) d[u][s] = D[s][u] = true, q.emplace(u, s);
                    }
                } else if(e.cost == ')') {
                    auto b = ~D[e] & x[u];
                    // dump(b);
                    for(int i = b._Find_first(); i < si(b); i = b._Find_next(i)) {
                        // dump(i);
                        d[i][e] = D[e][i] = true, q.emplace(i, e);
                    }
                } else if(e.cost == ']') {
                    auto b = ~D[e] & y[u];
                    for(int i = b._Find_first(); i < si(b); i = b._Find_next(i)) { d[i][e] = D[e][i] = true, q.emplace(i, e); }
                }
            }

            fore(e, rg[u]) {
                if(e.cost == '+' or e.cost == '*') {
                    // dump(e.to, u, v);
                    rep(s, n) {
                        if(d[s][e] and !d[s][v]) d[s][v] = D[v][s] = true, q.emplace(s, v);
                    }
                }
            }
        }
        Yes(d[s][t]);
    }
}
accuracy: 1
time_ms: 6020
memory_kb: 6144
final_rank: 17

code_snippet: #pragma GCC optimize("O3")
#pragma GCC optimize("unroll-loops")
#include<iostream>
#include<string>
#include<cstdio>
#include<vector>
#include<cmath>
#include<algorithm>
#include<functional>
#include<iomanip>
#include<queue>
#include<ciso646>
#include<random>
#include<map>
#include<set>
#include<bitset>
#include<stack>
#include<unordered_map>
#include<unordered_set>
#include<utility>
#include<cassert>
#include<complex>
#include<numeric>
#include<array>
#include<chrono>
using namespace std;

//#define int long long
typedef long long ll;

typedef unsigned long long ul;
typedef unsigned int ui;
constexpr ll mod = 10007;
const ll INF = mod * mod;
typedef pair<int, int>P;

#define rep(i,n) for(int i=0;i<n;i++)
#define per(i,n) for(int i=n-1;i>=0;i--)
#define Rep(i,sta,n) for(int i=sta;i<n;i++)
#define rep1(i,n) for(int i=1;i<=n;i++)
#define per1(i,n) for(int i=n;i>=1;i--)
#define Rep1(i,sta,n) for(int i=sta;i<=n;i++)
#define all(v) (v).begin(),(v).end()
typedef pair<ll, ll> LP;
typedef double ld;
typedef pair<ld, ld> LDP;
const ld eps = 1e-4;
const ld pi = acosl(-1.0);

template<typename T>
void chmin(T& a, T b) {
	a = min(a, b);
}
template<typename T>
void chmax(T& a, T b) {
	a = max(a, b);
}
template<typename T>
void cinarray(vector<T>& v) {
	rep(i, v.size())cin >> v[i];
}
template<typename T>
void coutarray(vector<T>& v) {
	rep(i, v.size()) {
		if (i > 0)cout << " "; cout << v[i];
	}
	cout << "\n";
}
ll mod_pow(ll x, ll n, ll m = mod) {
	if (n < 0) {
		ll res = mod_pow(x, -n, m);
		return mod_pow(res, m - 2, m);
	}
	if (abs(x) >= m)x %= m;
	if (x < 0)x += m;
	if (x == 0)return 0;
	ll res = 1;
	while (n) {
		if (n & 1)res = res * x % m;
		x = x * x % m; n >>= 1;
	}
	return res;
}
struct modint {
	int n;
	modint() :n(0) { ; }
	modint(ll m) {
		if (m < 0 || mod <= m) {
			m %= mod; if (m < 0)m += mod;
		}
		n = m;
	}
	operator int() { return n; }
};
bool operator==(modint a, modint b) { return a.n == b.n; }
modint operator+=(modint& a, modint b) { a.n += b.n; if (a.n >= mod)a.n -= mod; return a; }
modint operator-=(modint& a, modint b) { a.n -= b.n; if (a.n < 0)a.n += mod; return a; }
modint operator*=(modint& a, modint b) { a.n = ((ll)a.n * b.n) % mod; return a; }
modint operator+(modint a, modint b) { return a += b; }
modint operator-(modint a, modint b) { return a -= b; }
modint operator*(modint a, modint b) { return a *= b; }
modint operator^(modint a, ll n) {
	if (n == 0)return modint(1);
	modint res = (a * a) ^ (n / 2);
	if (n % 2)res = res * a;
	return res;
}

ll inv(ll a, ll p) {
	return (a == 1 ? 1 : (1 - p * inv(p % a, a)) / a + p);
}
modint operator/(modint a, modint b) { return a * modint(inv(b, mod)); }
modint operator/=(modint& a, modint b) { a = a / b; return a; }
const int max_n = 1 << 10;
modint fact[max_n], factinv[max_n];
void init_f() {
	fact[0] = modint(1);
	for (int i = 0; i < max_n - 1; i++) {
		fact[i + 1] = fact[i] * modint(i + 1);
	}
	factinv[max_n - 1] = modint(1) / fact[max_n - 1];
	for (int i = max_n - 2; i >= 0; i--) {
		factinv[i] = factinv[i + 1] * modint(i + 1);
	}
}
modint comb(int a, int b) {
	if (a < 0 || b < 0 || a < b)return 0;
	return fact[a] * factinv[b] * factinv[a - b];
}
modint combP(int a, int b) {
	if (a < 0 || b < 0 || a < b)return 0;
	return fact[a] * factinv[a - b];
}

ll gcd(ll a, ll b) {
	a = abs(a); b = abs(b);
	if (a < b)swap(a, b);
	while (b) {
		ll r = a % b; a = b; b = r;
	}
	return a;
}

int dx[4] = { 1,0,-1,0 };
int dy[4] = { 0,1,0,-1 };

//expr
//+term
//term
//*factor
//factor
//expr)
//expr]

struct ste {
	int i, j, t;
};
queue<ste> q;
bool added[200][200][7];
bool exi[200][200][7];
void add(int i, int j, int t) {
	if (added[i][j][t])return;
	added[i][j][t] = true;
	q.push({ i,j,t });
}
string ord = "()[]+*";
//()[]+*
vector<int> G[200][6];

int n, m, s, g;
void solve() {
	s--; g--;
	rep(i, n)rep(j, n)rep(k, 7) {
		added[i][j][k] = false;
		exi[i][j][k] = false;
	}
	rep(i, n)rep(t, 6)G[i][t].clear();
	while (!q.empty())q.pop();
	rep(i, m) {
		int a, b;char c; cin >> a >> b >> c; a--; b--;
		if (c == 'a')add(a, b, 4);
		else {
			int loc = ord.find(c);
			if (loc != 1 && loc != 3)swap(a, b);
			G[a][loc].push_back(b);
		}
	}
	while (!q.empty()) {
		//cout << q.size() << "\n";
		ste cur = q.front(); q.pop();
		int i = cur.i, j = cur.j, t = cur.t;
		exi[i][j][t] = true;
		if (i == s && j == g && t == 0) {
			cout << "Yes\n"; return;
		}
		if (t == 0) {
			//expr
			for (int to : G[j][1]) {
				add(i, to, 5);
			}
			for (int to : G[j][3]) {
				add(i, to, 6);
			}
			rep(to, n) {
				if (exi[j][to][1]) {
					add(i, to, 0);
				}
			}
		}
		else if (t == 1) {
			//+term
			rep(to, n) {
				if (exi[to][i][0]) {
					add(to, j, 0);
				}
			}
		}
		else if (t == 2) {
			//term
			for (int to : G[i][4]) {
				add(to, j, 1);
			}
			rep(to, n) {
				if (exi[j][to][3]) {
					add(i, to, 2);
				}
			}
			add(i, j, 0);
		}
		else if (t == 3) {
			//*factor
			rep(to, n) {
				if (exi[to][i][2]) {
					add(to, j, 2);
				}
			}
		}
		else if (t == 4) {
			//factor
			for (int to : G[i][5]) {
				add(to, j, 3);
			}
			add(i, j, 2);
		}
		else if (t == 5) {
			//expr)
			for (int to : G[i][0]) {
				add(to, j, 4);
			}
		}
		else {
			//expr]
			for (int to : G[i][2]) {
				add(to, j, 4);
			}
		}
	}
	cout << "No\n";
}


signed main() {
	ios::sync_with_stdio(false);
	cin.tie(0);
	//cout << fixed << setprecision(8);
	init_f();
	//init();
	//while(true)
	//expr();
	//int t; cin >> t; rep(i, t)
	while(cin>>n>>m>>s>>g,n)
	solve();
	return 0;
}
accuracy: 1
time_ms: 150
memory_kb: 6508
final_rank: 2

code_snippet: //Let's join Kaede Takagaki Fan Club !!
#pragma GCC optimize("Ofast")
#pragma GCC optimize("unroll-loops")
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <ctime>
#include <cassert>
#include <string>
#include <algorithm>
#include <vector>
#include <queue>
#include <stack>
#include <functional>
#include <iostream>
#include <map>
#include <set>
#include <unordered_map>
#include <unordered_set>
#include <cassert>
#include <iomanip>
#include <chrono>
#include <random>
#include <bitset>
#include <complex>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>
using namespace std;
#define int long long
//#define L __int128
typedef long long ll;
typedef pair<int,int> P;
typedef pair<int,P> P1;
typedef pair<P,P> P2;
#define pu push
#define pb push_back
#define eb emplace_back
#define mp make_pair
#define eps 1e-7
#define INF 1000000000
#define a first
#define b second
#define fi first
#define sc second
#define rng(i,a,b) for(int i=(int)(a);i<(int)(b);i++)
#define rep(i,x) for(int i=0;i<x;i++)
#define repn(i,x) for(int i=1;i<=x;i++)
#define SORT(x) sort(x.begin(),x.end())
#define ERASE(x) x.erase(unique(x.begin(),x.end()),x.end())
#define POSL(x,v) (lower_bound(x.begin(),x.end(),v)-x.begin())
#define POSU(x,v) (upper_bound(x.begin(),x.end(),v)-x.begin())
#define all(x) x.begin(),x.end()
#define si(x) int(x.size())
 
#ifdef LOCAL
#define dmp(x) cerr<<__LINE__<<" "<<#x<<" "<<x<<endl
#else
#define dmp(x) void(0)
#endif
 
template<class t,class u> bool chmax(t&a,u b){if(a<b){a=b;return true;}else return false;}
template<class t,class u> bool chmin(t&a,u b){if(b<a){a=b;return true;}else return false;}
 
template<class t> using vc=vector<t>;
 
template<class t,class u>
ostream& operator<<(ostream& os,const pair<t,u>& p){
	return os<<"{"<<p.fi<<","<<p.sc<<"}";
}
 
template<class t> ostream& operator<<(ostream& os,const vc<t>& v){
	os<<"{";
	for(auto e:v)os<<e<<",";
	return os<<"}";
}
 
template<class T>
void g(T &a){
	cin >> a;
}
template<class T>
void o(const T &a,bool space=false){
	cout << a << (space?' ':'\n');
}
//ios::sync_with_stdio(false);
//const ll mod = 998244353;
const ll mod = 1000000007;
mt19937_64 mt(chrono::steady_clock::now().time_since_epoch().count());
template<class T>
void add(T&a,T b){
	a+=b;
	if(a >= mod) a-=mod;
}
ll modpow(ll x,ll n){
	ll res=1;
	while(n>0){
		if(n&1) res=res*x%mod;
		x=x*x%mod;
		n>>=1;
	}
	return res;
}
#define _sz 1
ll F[_sz],R[_sz];
void make(){
	F[0] = 1;
	for(int i=1;i<_sz;i++) F[i] = F[i-1]*i%mod;
	R[_sz-1] = modpow(F[_sz-1], mod-2);
	for(int i=_sz-2;i>=0;i--) R[i] = R[i+1] * (i+1) % mod;
}
ll C(int a,int b){
	if(b < 0 || a < b) return 0;
	return F[a]*R[b]%mod*R[a-b]%mod;
}

//複数テストケースなので積み上げる変数はローカルに！
//置けないなら必ず初期化！
int n, m, s, t;
bool ex[205][205][8];
bool dp[205][205][5];
void solve(){
	//最初の入力は済んでいる
	memset(ex, 0, sizeof(ex));
	memset(dp, 0, sizeof(dp));
	queue<int>que;
	rep(i, m){
		int a, b; string _c; cin >> a >> b >> _c;
		a --; b --;
		char c = _c[0];
		int num;
		if(c == 'a') num = 0;
		else if(c == '+' or c == '*') num = 1;
		else if(c == '(') num = 2;
		else if(c == '[') num = 3;
		else if(c == ')') num = 6;
		else num = 7;
		ex[a][b][num] = 1;
		if(num == 0 and !dp[a][b][0]){
			dp[a][b][0] = 1;
			que.push(a * 1000000 + b * 1000 + 0);
		}
	}
	while(!que.empty()){
		auto qq = que.front(); que.pop();
		int s = qq / 1000000; qq %= 1000000;
		int t = qq / 1000; qq %= 1000;
		int u = qq;
		if(u == 0){
			//0 -> 1, 2, 3, 4
			rep(pre, n) if(ex[pre][s][1] and !dp[pre][t][1]){
				dp[pre][t][1] = 1;
				que.push(pre * 1000000 + t * 1000 + 1);
			}
			rep(nxt, n){
				if(ex[t][nxt][6] and !dp[s][nxt][2]){
					dp[s][nxt][2] = 1;
					que.push(s * 1000000 + nxt * 1000 + 2);
				}
				if(ex[t][nxt][7] and !dp[s][nxt][3]){
					dp[s][nxt][3] = 1;
					que.push(s * 1000000 + nxt * 1000 + 3);
				}
				if(ex[t][nxt][1] and !dp[s][nxt][4]){
					dp[s][nxt][4] = 1;
					que.push(s * 1000000 + nxt * 1000 + 4);
				}
			}
		}
		else if(u == 1){
			rep(pre, n) if(dp[pre][s][0] and !dp[pre][t][0]){
				dp[pre][t][0] = 1;
				que.push(pre * 1000000 + t * 1000 + 0);
			}
		}
		else if(u == 4){
			rep(nxt, n) if(dp[t][nxt][0] and !dp[s][nxt][0]){
				dp[s][nxt][0] = 1;
				que.push(s * 1000000 + nxt * 1000 + 0);
			}
		}
		else{
			rep(pre, n) if(ex[pre][s][u] and !dp[pre][t][0]){
				dp[pre][t][0] = 1;
				que.push(pre * 1000000 + t * 1000 + 0);
			}
		}
	}
	o(dp[s][t][0]?"Yes":"No");
}
signed main(){
	//cin.tie(0);
	ios::sync_with_stdio(0);
	cout<<fixed<<setprecision(20);
	while(true){
		cin>>n>>m>>s>>t;
		s--;t--;
		//終了条件
		if(!n) return 0;
		solve();
	}
}
accuracy: 1
time_ms: 450
memory_kb: 5144
final_rank: 3

code_snippet: /**
 *    author:  otera
 *    created: 25.10.2021 17:54:41 
**/
#include<bits/stdc++.h>
using namespace std;

using ll = long long;
using ld = long double;
using ull = unsigned long long;
using uint = unsigned;
#define repa(i, n) for(int i = 0; i < n; ++ i)
#define repb(i, a, b) for(int i = a; i < b; ++ i)
#define repc(i, a, b, c) for(int i = a; i < b; i += c)
#define overload4(a, b, c, d, e, ...) e
#define rep(...) overload4(__VA_ARGS__, repc, repb, repa)(__VA_ARGS__)
#define rep1a(i, n) for(int i = 0; i <= n; ++ i)
#define rep1b(i, a, b) for(int i = a; i <= b; ++ i)
#define rep1c(i, a, b, c) for(int i = a; i <= b; i += c)
#define rep1(...) overload4(__VA_ARGS__, rep1c, rep1b, rep1a)(__VA_ARGS__)
#define per(i,n) for(int i=n-1;i>=0;i--)
#define per1(i,n) for(int i=n;i>=1;i--)
typedef pair<ll, ll> LP;
#define pb push_back
#define eb emplace_back
#define fr first
#define sc second
#define all(c) c.begin(),c.end()
#define lb(c, x) distance((c).begin(), lower_bound(all(c), (x)))
#define ub(c, x) distance((c).begin(), upper_bound(all(c), (x)))
#define Sort(a) sort(all(a))
#define Rev(a) reverse(all(a))
#define Uniq(a) sort(all(a));a.erase(unique(all(a)),end(a))
#define si(c) (int)(c).size()
inline ll popcnt(ull a){ return __builtin_popcountll(a); }
#define tpow(n) (1LL<<(n))
#define unless(A) if(!(A))
ll intpow(ll a, ll b){ ll ans = 1; while(b){ if(b & 1) ans *= a; a *= a; b /= 2; } return ans; }
ll intpow(ll a, ll b, ll m) {ll ans = 1; while(b){ if(b & 1) (ans *= a) %= m; (a *= a) %= m; b /= 2; } return ans; }
template<class T> inline bool chmax(T& a, T b) { if (a < b) { a = b; return 1; } return 0; }
template<class T> inline bool chmin(T& a, T b) { if (a > b) { a = b; return 1; } return 0; }
#define INT(...) int __VA_ARGS__;in(__VA_ARGS__)
#define LL(...) ll __VA_ARGS__;in(__VA_ARGS__)
#define ULL(...) ull __VA_ARGS__;in(__VA_ARGS__)
#define STR(...) string __VA_ARGS__;in(__VA_ARGS__)
#define CHR(...) char __VA_ARGS__;in(__VA_ARGS__)
#define DBL(...) double __VA_ARGS__;in(__VA_ARGS__)
#define LD(...) ld __VA_ARGS__;in(__VA_ARGS__)
#define vec(type,name,...) vector<type>name(__VA_ARGS__)
#define VEC(type,name,size) vector<type>name(size);in(name)
#define vv(type,name,h,...) vector<vector<type>>name(h,vector<type>(__VA_ARGS__))
#define VV(type,name,h,w) vector<vector<type>>name(h,vector<type>(w));in(name)
#define vvv(type,name,h,w,...) vector<vector<vector<type>>>name(h,vector<vector<type>>(w,vector<type>(__VA_ARGS__)))
template <class T> using vc = vector<T>;
template <class T> using vvc = vector<vc<T>>;
template <class T> using vvvc = vector<vvc<T>>;
template <class T> using vvvvc = vector<vvvc<T>>;
template <class T> using pq = priority_queue<T>;
template <class T> using pqg = priority_queue<T, vector<T>, greater<T>>;
template<class T> void scan(T& a){ cin >> a; }
template<class T> void scan(vector<T>& a){ for(auto&& i : a) scan(i); }
void in(){}
template <class Head, class... Tail> void in(Head& head, Tail&... tail){ scan(head); in(tail...); }
void print(){ cout << ' '; }
template<class T> void print(const T& a){ cout << a; }
template<class T> void print(const vector<T>& a){ if(a.empty()) return; print(a[0]); for(auto i = a.begin(); ++i != a.end(); ){ cout << ' '; print(*i); } }
int out(){ cout << '\n'; return 0; }
template<class T> int out(const T& t){ print(t); cout << '\n'; return 0; }
template<class Head, class... Tail> int out(const Head& head, const Tail&... tail){ print(head); cout << ' '; out(tail...); return 0; }
#define CHOOSE(a) CHOOSE2 a
#define CHOOSE2(a0,a1,a2,a3,a4,x,...) x
#define debug_1(x1) cout<<#x1<<": "<<x1<<endl
#define debug_2(x1,x2) cout<<#x1<<": "<<x1<<", "#x2<<": "<<x2<<endl
#define debug_3(x1,x2,x3) cout<<#x1<<": "<<x1<<", "#x2<<": "<<x2<<", "#x3<<": "<<x3<<endl
#define debug_4(x1,x2,x3,x4) cout<<#x1<<": "<<x1<<", "#x2<<": "<<x2<<", "#x3<<": "<<x3<<", "#x4<<": "<<x4<<endl
#define debug_5(x1,x2,x3,x4,x5) cout<<#x1<<": "<<x1<<", "#x2<<": "<<x2<<", "#x3<<": "<<x3<<", "#x4<<": "<<x4<<", "#x5<<": "<<x5<<endl
#ifdef DEBUG
#define debug(...) CHOOSE((__VA_ARGS__,debug_5,debug_4,debug_3,debug_2,debug_1,~))(__VA_ARGS__)
#define dump(...) { print(#__VA_ARGS__); print(":"); out(__VA_ARGS__); }
#else
#define debug(...)
#define dump(...)
#endif

#define int long long

typedef pair<int, char> P;

// expression -> aに置き換えてok

// a    0
// ( a  1
// [ a  2
// a +  3
// + a  4
bool dp[250][250][5];
// a 0
// + or * 1
// ( 2
// ) 3
// [ 4
// ] 5
bool e[250][250][6];
queue<pair<int, int>> que[5], nque[5];

void solve() {
    int n, m, s, t;
    while(cin >> n >> m >> s >> t) {
        if(n == 0 and m == 0 and s == 0 and t == 0) break;
        -- s, -- t;
        // clear
        rep(i, n) {
            rep(j, n) {
                rep(k, 5) {
                    dp[i][j][k] = 0;
                }
            }
        }
        rep(i, n) {
            rep(j, n) {
                rep(k, 6) {
                    e[i][j][k] = 0;
                }
            }
        }
        rep(k, 5) {
            while(que[k].size()) que[k].pop();
            while(nque[k].size()) nque[k].pop();
        }
        // calc
        vvc<P> g(n);
        rep(i, m) {
            INT(a, b); -- a, -- b;
            CHR(c);
            // debug(a, b, c);
            if(c == '*') c = '+';
            g[a].eb(b, c);
            // g[b].eb(a, c);
            if(c == 'a') {
                dp[a][b][0] = 1;
                e[a][b][0] = 1;
                // e[b][a][0] = 1;
                // debug(a, b);
                que[0].push({a, b});
                // que[0].push({b, a});
            } else if(c == '+') e[a][b][1] = 1;
            else if(c == '(') e[a][b][2] = 1;
            else if(c == ')') e[a][b][3] = 1;
            else if(c == '[') e[a][b][4] = 1;
            else if(c == ']') e[a][b][5] = 1;
        }
        while(que[0].size() or que[1].size() or que[2].size() or que[3].size() or que[4].size()) {
            // rep(k, 4) {
            //     while(que[k].size()) {
            //         auto [a, b] = que[k].front(); que[k].pop();
            //         rep(c, n) {
            //             // calc
            //         }
            //     }
            // }
            // a
            while(que[0].size()) {
                auto [a, b] = que[0].front();
                que[0].pop();
                debug(a, b);
                rep(c, n) {
                    // c - a == '('
                    if(e[c][a][2]) {
                        unless(dp[c][b][1]) {
                            dp[c][b][1] = 1;
                            nque[1].push({c, b});
                        }
                    }
                    // c - a == '['
                    if(e[c][a][4]) {
                        unless(dp[c][b][2]) {
                            dp[c][b][2] = 1;
                            nque[2].push({c, b});
                        }
                    }
                    // b - c == '+'
                    if(e[b][c][1]) {
                        unless(dp[a][c][3]) {
                            dp[a][c][3] = 1;
                            nque[3].push({a, c});
                        }
                    }
                    // c - a == '+'
                    if(e[c][a][1]) {
                        unless(dp[c][b][4]) {
                            dp[c][b][4] = 1;
                            nque[4].push({c, b});
                        }
                    }
                }
            }
            // ( a
            while(que[1].size()) {
                auto [a, b] = que[1].front(); que[1].pop();
                rep(c, n) {
                    // b - c == ')'
                    if(e[b][c][3]) {
                        unless(dp[a][c][0]) {
                            dp[a][c][0] = 1;
                            nque[0].push({a, c});
                        }
                    }
                }
            }
            // [ a
            while(que[2].size()) {
                auto [a, b] = que[2].front(); que[2].pop();
                rep(c, n) {
                    // b - c == ']'
                    if(e[b][c][5]) {
                        unless(dp[a][c][0]) {
                            dp[a][c][0] = 1;
                            nque[0].push({a, c});
                        }
                    }
                }
            }
            // a +
            while(que[3].size()) {
                auto [a, b] = que[3].front(); que[3].pop();
                rep(c, n) {
                    // b - c == 'a' == expression
                    if(dp[b][c][0]) {
                        unless(dp[a][c][0]) {
                            dp[a][c][0] = 1;
                            nque[0].push({a, c});
                        }
                    }
                }
            }
            // + a
            while(que[4].size()) {
                auto [a, b] = que[4].front(); que[4].pop();
                rep(c, n) {
                    // c - a == 'a' == expression
                    if(dp[c][a][0]) {
                        unless(dp[c][b][0]) {
                            dp[c][b][0] = 1;
                            nque[0].push({c, b});
                        }
                    }
                }
            }
            rep(k, 5) {
                swap(que[k], nque[k]);
            }
        }
        out(dp[s][t][0] ? "Yes" : "No");
    }
}

signed main() {
    ios::sync_with_stdio(false);
    cin.tie(0);
    // cout << fixed << setprecision(20);
    // INT(t); rep(i, t)solve();
    solve();
    return 0;
}
accuracy: 1
time_ms: 370
memory_kb: 8864
final_rank: 5