Problem:
Problem I:
夏への扉
なつめは大のねこ好きである。なつめの家ではずっとねこを飼っておらず、ねこ好きななつめはいつも野良ねこと遊んでいた。しかし、今回なつめは決心し、自分の家でねこを一匹飼うことにした。なつめはねこを家に迎え、レノンと名付けてかわいがり始めた。
なつめの家はたくさんの部屋と、それらをつなぐたくさんの扉からなっており、扉は次の2種類がある。
人間用の普通の扉
なつめは開けることができるが、レノンが自分で開けることはできない。なつめとレノンの両方が通ることができる。一度開ければ、その後は開いたままにしておける。
ねこ用の小さな扉
レノンが自分であけて自由に通ることができる。ただし小さいために、なつめが通ることはできない。
レノンは夏が大好きである。だから、冬になり家の外がまっしろな雪で覆われてしまう頃になると、彼の機嫌はとても悪くなってしまった。しかし、彼は家にたくさんあるドアのうち、あるひとつの扉が「夏」へとつながっていると信じているようだった。なつめはその扉を「夏への扉」と呼んでいる。そして、寒くて不機嫌になってくると、レノンはきまってその扉の向こうへ行きたがるのである。
冬のある日、レノンがまた「夏への扉」の奥へ行こうと思い立った。しかし、レノンがひとりで扉を開けて、夏への扉の奥へ行けるとは限らない。その時はもちろん、なつめはレノンの手伝いをしなければならない。つまり、なつめしか開けることの出来ない扉をいくつか開いて、レノンが「夏への扉」の向こう側へ行けるようにしてあげるのだ。
最初、家の中の全ての扉は閉まっている。家の部屋の接続関係、なつめおよびレノンの初期位置が与えられる。なつめとレノンが最適な戦略をとった時、レノンが「夏への扉」の先へいくために
なつめが開けなければならない扉
の最小数を計算しなさい。
以下の図は、サンプル入力の例を図示したものである。
図: サンプル入力の初期状態
Input
入力の1行目には、部屋の数
n
と扉の数
m
が1つの空白文字で区切って与えられる。部屋にはそれぞれ 0 から
n
の番号が割り振られており、0は「夏への扉」の先をあらわす。2行目はなつめが最初にいる部屋の番号とレノンが最初にいる部屋の番号が、1つの空白文字で区切って与えられる。どちらの部屋番号も1以上であり、最初から「夏への扉」の先にいることはない。続く
m
行には、
m
枚の扉の情報がそれぞれ1行ずつ与えられる。各行はふたつの部屋IDと扉の種類を表す1文字のアルファベットからなり、1つの空白文字で区切られている。扉は指定されたふたつの部屋を繋いでおり、種類はアルファベットが
N
のとき人間用の普通の扉、
L
のときねこ用の小さな扉である。扉が同じ部屋同士を繋ぐことはない。部屋IDが0のものを含む扉が「夏への扉」であり、これは入力中に必ずただ1つ存在する。1 <= n, m <= 100000を満たす。
Output
なつめが開けなければならない扉の最小数を、1行で出力せよ。
Notes on Submission
上記形式で複数のデータセットが与えられます。入力データの 1 行目にデータセットの数が与えられます。各データセットに対する出力を上記形式で順番に出力するプログラムを作成して下さい。
Sample Input
2
4 6
1 2
1 2 N
2 3 N
3 4 N
4 1 N
1 4 L
4 0 L
4 6
1 2
1 2 N
2 3 N
3 4 N
4 1 N
1 4 L
4 0 N
Output for the Sample Input
1
3

Submitted solutions:

code_snippet: #include <bits/stdc++.h>
using namespace std;
using ll=int64_t;

int main(){

  int cnt;
  cin >> cnt;
  int n,m,hs,cs;
  for(int k=0;k<cnt;k++){
    cin >> n >> m;
    cin >> hs >> cs;
    
    vector<vector<int>> dh(n+1),dc(n+1);
    int a,b;
    char c;
    for(int i=0;i<m;i++){
      cin >> a >> b >> c;
      if(c=='N'){
        dh[a].push_back(b);
        dh[b].push_back(a);
      }else{
        dc[a].push_back(b);
        dc[b].push_back(a);
        
      }
    }
    
    vector<bool> cfs(n+1,false),ctg(n+1,false);
    vector<int> cfsd(n+1,INT_MAX),ctgd(n+1,INT_MAX),hfsd(n+1,INT_MAX);
    cfs[cs]=true;
    ctg[0]=true;
    queue<int> que,ques,queg;
    que.push(cs);
    ques.push(cs);
    cfsd[cs]=0;
    while(!que.empty()){
      int cp=que.front();
      que.pop();
      for(int i=0;i<(int)dc[cp].size();i++){
        if(!cfs[dc[cp][i]]){ 
          cfs[dc[cp][i]]=true;
          que.push(dc[cp][i]);
          ques.push(dc[cp][i]);
          cfsd[dc[cp][i]]=0;
        }
      }
    }
    if(cfs[0]){
      cout << 0 << endl;
      continue;
    }
    
    que.push(0);
    queg.push(0);
    ctgd[0]=0;
    while(!que.empty()){
      int cp=que.front();
      que.pop();
      for(int i=0;i<(int)dc[cp].size();i++){
        if(!ctg[dc[cp][i]]){ 
          ctg[dc[cp][i]]=true;
          que.push(dc[cp][i]);
          queg.push(dc[cp][i]);
          ctgd[dc[cp][i]]=0;
        }
      }
    }
    
    while(!ques.empty()){
      int cp=ques.front();
      ques.pop();
      for(int i=0;i<(int)dh[cp].size();i++){
        if(cfsd[dh[cp][i]]==INT_MAX){
          cfsd[dh[cp][i]]=cfsd[cp]+1;
          ques.push(dh[cp][i]);
        }
      }
    }
    while(!queg.empty()){
      int cp=queg.front();
      queg.pop();
      for(int i=0;i<(int)dh[cp].size();i++){
        if(ctgd[dh[cp][i]]==INT_MAX){
          ctgd[dh[cp][i]]=ctgd[cp]+1;
          queg.push(dh[cp][i]);
        }
      }
    }
    
    hfsd[hs]=0;
    que.push(hs);
    while(!que.empty()){
      int hp=que.front();
      que.pop();
      for(int i=0;i<(int)dh[hp].size();i++){
        if(hfsd[dh[hp][i]]==INT_MAX){
          hfsd[dh[hp][i]]=hfsd[hp]+1;
          que.push(dh[hp][i]);
        }
      }
    }
    
    int ans=INT_MAX;
    for(int i=0;i<=n;i++){
      if((cfsd[i]==INT_MAX)||(ctgd[i]==INT_MAX)||(hfsd[i]==INT_MAX)) continue;
      ans=min(ans,cfsd[i]+ctgd[i]+hfsd[i]);
    }
    cout << ans << endl;
  }
  return 0;
}
accuracy: 1
time_ms: 160
memory_kb: 12064
final_rank: 5

code_snippet: #pragma GCC optimize("Ofast")
#include <iostream>
#include <vector>
#include <algorithm>
#include <map>
#include <queue>
#include <cstdio>
#include <ctime>
#include <assert.h>
#include <chrono>
#include <random>
#include <numeric>
#include <set>
#include <deque>
#include <stack>
#include <sstream>
#include <utility>
#include <cstring>
#include <unordered_map>
#include <unordered_set>
#include <tuple>
#include <array>
#include <bitset>
using namespace std;
typedef long long int ll;
typedef unsigned long long ull;

mt19937_64 rng(chrono::steady_clock::now().time_since_epoch().count());
ll myRand(ll B) {
    return (ull)rng() % B;
}
inline double time() {
    return static_cast<double>(chrono::duration_cast<chrono::nanoseconds>(chrono::steady_clock::now().time_since_epoch()).count()) * 1e-9;
}

struct UnionFind{
    vector<int> par,num;
    UnionFind(int n):par(n),num(n,1){
        iota(par.begin(),par.end(),0);  //include<numeric>
    }
    int find(int v){
        return (par[v]==v)?v:(par[v]=find(par[v]));
    }
    void unite(int u,int v){
        u=find(u),v=find(v);
        if(u==v)return;
        if(num[u]<num[v])swap(u,v);
        num[u]+=num[v];
        par[v]=u;
    }
    bool same(int u,int v){
        return find(u) == find(v);
    }
    int size(int v){
        return num[find(v)];
    }
};

int main(){
    cin.tie(nullptr);
    ios::sync_with_stdio(false);
    int qq; cin >> qq;
    while(qq--){
        int n,m; cin >> n >> m;
        UnionFind uf(n+1);
        vector<vector<int>> g(n+1);
        int na,le; cin >> na >> le;
        for(int i=0;i<m;i++){
            int x,y; cin >> x >> y;
            char c; cin >> c;
            if(c == 'N'){
                g[x].push_back(y);
                g[y].push_back(x);
            }
            else{
                uf.unite(x, y);
            }
        }
        if(uf.same(le, 0)){
            cout << 0 << "\n"; continue;
        }
        vector<int> dp1(n+1,-1);
        dp1[na] = 0;
        queue<int> q; q.push(na);
        while(q.size()){
            int s = q.front(); q.pop();
            for(int t:g[s]){
                if(dp1[t] == -1){
                    dp1[t] = dp1[s]+1;
                    q.push(t);
                }
            }
        }
        vector<int> dp2(n+1,-1);
        for(int i=0;i<=n;i++){
            if(uf.same(le, i)){
                dp2[i] = 0; q.push(i);
            }
        }
        while(q.size()){
            int s = q.front(); q.pop();
            for(int t:g[s]){
                if(dp2[t] == -1){
                    dp2[t] = dp2[s]+1;
                    q.push(t);
                }
            }
        }
        vector<int> dp3(n+1,-1);
        for(int i=0;i<=n;i++){
            if(uf.same(0, i)){
                dp3[i] = 0; q.push(i);
            }
        }
        while(q.size()){
            int s = q.front(); q.pop();
            for(int t:g[s]){
                if(dp3[t] == -1){
                    dp3[t] = dp3[s]+1;
                    q.push(t);
                }
            }
        }
        int res = 1e9;
        for(int i=0;i<=n;i++){
            if(dp1[i] == -1 or dp2[i] == -1 or dp3[i] == -1)continue;
            res = min(res, dp1[i]+dp2[i]+dp3[i]);
        }
        cout << res << "\n";
    }
}
accuracy: 1
time_ms: 70
memory_kb: 10332
final_rank: 1

code_snippet: #pragma GCC optimize("Ofast")
#include <iostream>
#include <vector>
#include <algorithm>
#include <map>
#include <queue>
#include <cstdio>
#include <ctime>
#include <assert.h>
#include <chrono>
#include <random>
#include <numeric>
#include <set>
#include <deque>
#include <stack>
#include <sstream>
#include <utility>
#include <cstring>
#include <unordered_map>
#include <unordered_set>
#include <tuple>
#include <array>
#include <bitset>
using namespace std;
typedef long long int ll;
typedef unsigned long long ull;

mt19937_64 rng(chrono::steady_clock::now().time_since_epoch().count());
ll myRand(ll B) {
    return (ull)rng() % B;
}
inline double time() {
    return static_cast<double>(chrono::duration_cast<chrono::nanoseconds>(chrono::steady_clock::now().time_since_epoch()).count()) * 1e-9;
}

struct UnionFind{
    vector<int> par,num;
    UnionFind(int n):par(n),num(n,1){
        iota(par.begin(),par.end(),0);  //include<numeric>
    }
    int find(int v){
        return (par[v]==v)?v:(par[v]=find(par[v]));
    }
    void unite(int u,int v){
        u=find(u),v=find(v);
        if(u==v)return;
        if(num[u]<num[v])swap(u,v);
        num[u]+=num[v];
        par[v]=u;
    }
    bool same(int u,int v){
        return find(u) == find(v);
    }
    int size(int v){
        return num[find(v)];
    }
};

int main(){
    cin.tie(nullptr);
    ios::sync_with_stdio(false);
    int qq; cin >> qq;
    while(qq--){
        int n,m; cin >> n >> m;
        UnionFind uf(n+1);
        vector<vector<int>> g(n+1);
        int na,le; cin >> na >> le;
        for(int i=0;i<m;i++){
            int x,y; cin >> x >> y;
            char c; cin >> c;
            if(c == 'N'){
                g[x].push_back(y);
                g[y].push_back(x);
            }
            else{
                uf.unite(x, y);
            }
        }
        if(uf.same(le, 0)){
            cout << 0 << "\n"; continue;
        }
        vector<int> dp1(n+1,-1);
        dp1[na] = 0;
        queue<int> q; q.push(na);
        while(q.size()){
            int s = q.front(); q.pop();
            for(int t:g[s]){
                if(dp1[t] == -1){
                    dp1[t] = dp1[s]+1;
                    q.push(t);
                }
            }
        }
        vector<int> dp2(n+1,-1);
        for(int i=0;i<=n;i++){
            if(uf.same(le, i)){
                dp2[i] = 0; q.push(i);
            }
        }
        while(q.size()){
            int s = q.front(); q.pop();
            for(int t:g[s]){
                if(dp2[t] == -1){
                    dp2[t] = dp2[s]+1;
                    q.push(t);
                }
            }
        }
        vector<int> dp3(n+1,-1);
        for(int i=0;i<=n;i++){
            if(uf.same(0, i)){
                dp3[i] = 0; q.push(i);
            }
        }
        while(q.size()){
            int s = q.front(); q.pop();
            for(int t:g[s]){
                if(dp3[t] == -1){
                    dp3[t] = dp3[s]+1;
                    q.push(t);
                }
            }
        }
        int res = 1e9;
        for(int i=0;i<=n;i++){
            if(dp1[i] == -1 or dp2[i] == -1 or dp3[i] == -1)continue;
            res = min(res, dp1[i]+dp2[i]+dp3[i]);
        }
        cout << res << "\n";
    }
}
accuracy: 1
time_ms: 70
memory_kb: 10480
final_rank: 2

code_snippet: #include <iostream>
#include <utility>
#include <tuple>
#include <vector>
#include <string>
#include <map>
#include <unordered_map>
#include <set>
#include <unordered_set>
#include <algorithm>
#include <functional>
#include <climits>
#include <numeric>
#include <queue>
#include <cmath>
#include <iomanip>
#include <array>
#include <string>
#include <stack>
#include <cassert>
#include <memory>
#include <random>


int main() {
	int t; std::cin >> t;
	for (; t > 0; --t) {
		int n, m; std::cin >> n >> m;
		int human_start, cat_start; std::cin >> human_start >> cat_start;
		std::vector<std::vector<int>> rooms(n + 1), for_cat(n + 1);
		for (auto i = 0; i < m; ++i) {
			int a, b; std::string type; std::cin >> a >> b >> type;
			if (type == "N") {
				rooms[a].push_back(b);
				rooms[b].push_back(a);
			}
			else {
				for_cat[a].push_back(b);
				for_cat[b].push_back(a);
			}
		}
		std::queue<int> queue;
		std::vector<bool> can_move_from_start(n + 1, false), can_move_to_goal(n + 1, false);
		can_move_from_start[cat_start] = true; queue.push(cat_start);
		while (!queue.empty()) {
			const auto top = queue.front(); queue.pop();
			for (const auto next : for_cat[top]) if (!can_move_from_start[next]) {
				can_move_from_start[next] = true;
				queue.push(next);
			}
		}
		can_move_to_goal[0] = true; queue.push(0);
		while (!queue.empty()) {
			const auto top = queue.front(); queue.pop();
			for (const auto next : for_cat[top]) if (!can_move_to_goal[next]) {
				can_move_to_goal[next] = true;
				queue.push(next);
			}
		}
		std::vector<int> from_start(n + 1, INT_MAX), to_goal(n + 1, INT_MAX), from_cat(n + 1, INT_MAX);
		for (auto i = 0; i < can_move_to_goal.size(); ++i) if (can_move_to_goal[i]) {
			to_goal[i] = 0; queue.push(i);
		}
		while (!queue.empty()) {
			const auto top = queue.front(); queue.pop();
			for (const auto next : rooms[top]) if (to_goal[next] == INT_MAX) {
				to_goal[next] = to_goal[top] + 1;
				queue.push(next);
			}
		}
		from_start[human_start] = 0; queue.push(human_start);
		while (!queue.empty()) {
			const auto top = queue.front(); queue.pop();
			for (const auto next : rooms[top]) if (from_start[next] == INT_MAX) {
				from_start[next] = from_start[top] + 1;
				queue.push(next);
			}
		}
		for (auto i = 0; i < can_move_from_start.size(); ++i) if (can_move_from_start[i]) {
			from_cat[i] = 0; queue.push(i);
		}
		while (!queue.empty()) {
			const auto top = queue.front(); queue.pop();
			for (const auto next : rooms[top]) if (from_cat[next] == INT_MAX) {
				from_cat[next] = from_cat[top] + 1;
				queue.push(next);
			}
		}
		int min_open = INT_MAX;
		for (auto i = 0; i < n + 1; ++i) {
			if (from_start[i] == INT_MAX || to_goal[i] == INT_MAX || from_cat[i] == INT_MAX) continue;
			if (can_move_from_start[i] && can_move_to_goal[i]) {
				min_open = 0;
				break;
			}
			min_open = std::min(min_open, from_start[i] + to_goal[i] + from_cat[i]);
		}
		std::cout << min_open << '\n';
	}
}
accuracy: 1
time_ms: 250
memory_kb: 11936
final_rank: 12

code_snippet: #include<bits/stdc++.h>
typedef long long int ll;
typedef unsigned long long int ull;
#define BIG_NUM 2000000000
#define HUGE_NUM 99999999999999999
#define MOD 1000000007
#define EPS 0.000000001
using namespace std;


#define NUM 100005

enum Type{
	base_human,
	base_cat,
	base_can_area,
};

struct Info{
	Info(int arg_room_id,int arg_sum_cost){
		room_id = arg_room_id;
		sum_cost = arg_sum_cost;
	}
	bool operator<(const struct Info &arg) const{
		return sum_cost > arg.sum_cost;
	}
	int room_id,sum_cost;
};

int goal;
int num_room,num_door;
int min_dist[3][NUM];
int height[NUM],boss[NUM];
vector<int> human_G[NUM],cat_G[NUM];

int get_boss(int id){
	if(boss[id] == id)return id;
	else{
		return boss[id] = get_boss(boss[id]);
	}
}

int is_same_group(int x,int y){
	return get_boss(x) == get_boss(y);
}

void unite(int x,int y){
	int boss_x = get_boss(x);
	int boss_y = get_boss(y);

	//既に同じグループなら何もしない
	if(boss_x == boss_y)return;

	//高さが高い方に吸収する
	if(height[x] > height[y]){

		boss[boss_y] = boss_x;

	}else if(height[x] < height[y]){

		boss[boss_x] = boss_y;

	}else{ //height[x] == height[y]

		boss[boss_y] = boss_x;
		height[x]++;
	}
}

void init(){
	for(int i = 0; i <= num_room; i++){ //★0が「夏への扉」の先★
		boss[i] = i;
		height[i] = 0;
	}
}

void func(){

	for(int i = 0; i <= num_room; i++){
		human_G[i].clear();
		cat_G[i].clear();
	}

	scanf("%d %d",&num_room,&num_door);

	init();

	int start_human,start_cat;
	scanf("%d %d",&start_human,&start_cat);

	int from,to;
	char buf[2];

	for(int loop = 0; loop < num_door; loop++){
		scanf("%d %d %s",&from,&to,buf);

		if(buf[0] == 'N'){ //人間用

			human_G[from].push_back(to);
			human_G[to].push_back(from);

		}else{ //猫用

			unite(from,to);

			cat_G[from].push_back(to);
			cat_G[to].push_back(from);
		}
	}

	//最初から自力ゴール可能な領域にいる場合
	if(is_same_group(goal,start_cat)){
		printf("0\n");
		return;
	}

	/*
	 * 人間がある部屋に移動する際の最小コストは猫の動きに無関係
	 */
	for(int i = 0; i <= num_room; i++)min_dist[base_human][i] = BIG_NUM;

	priority_queue<Info> Q;
	min_dist[base_human][start_human] = 0;
	Q.push(Info(start_human,0));

	int next_room,next_cost;

	//人間がある部屋に移動する最短コストを求める(通過できないので、猫用のエッジは無視)
	while(!Q.empty()){

		if(Q.top().sum_cost > min_dist[base_human][Q.top().room_id]){

			Q.pop();

		}else{

			next_cost = Q.top().sum_cost+1;

			for(int i = 0; i < human_G[Q.top().room_id].size(); i++){

				next_room = human_G[Q.top().room_id][i];

				if(min_dist[base_human][next_room] > next_cost){
					min_dist[base_human][next_room] = next_cost;
					Q.push(Info(next_room,next_cost));
				}
			}
			Q.pop();
		}
	}

	//[猫の初期稼働範囲]への、人間が到達する最短コストを逆算で求める
	for(int i = 0; i <= num_room; i++)min_dist[base_cat][i] = BIG_NUM;

	min_dist[base_cat][start_cat] = 0;
	Q.push(Info(start_cat,0));

	while(!Q.empty()){

		if(Q.top().sum_cost > min_dist[base_cat][Q.top().room_id]){

			Q.pop();

		}else{

			if(Q.top().sum_cost == 0){ //★★start地点から移動可能な範囲のみ、猫扉で移動(猫が可能な限り動いた方が最適)★★

				//猫用エッジ
				for(int i = 0; i < cat_G[Q.top().room_id].size(); i++){
					next_room = cat_G[Q.top().room_id][i];

					if(is_same_group(start_cat,next_room)){ //猫がstart地点から自力で辿り着ける部屋

						next_cost = Q.top().sum_cost;

					}else{

						next_cost = Q.top().sum_cost+1;
					}

					if(min_dist[base_cat][next_room] > next_cost){
						min_dist[base_cat][next_room] = next_cost;
						Q.push(Info(next_room,next_cost));
					}
				}
			}
			//人間用エッジ
			for(int i = 0; i < human_G[Q.top().room_id].size(); i++){

				next_room = human_G[Q.top().room_id][i];

				if(is_same_group(start_cat,next_room)){ //猫がstart地点から自力で辿り着ける部屋

					next_cost = Q.top().sum_cost;

				}else{

					next_cost = Q.top().sum_cost+1;
				}

				if(min_dist[base_cat][next_room] > next_cost){
					min_dist[base_cat][next_room] = next_cost;
					Q.push(Info(next_room,next_cost));
				}
			}

			Q.pop();
		}
	}

	//[猫が自力でゴールできる領域]への最短コストを求める
	for(int i = 0; i <= num_room; i++)min_dist[base_can_area][i] = BIG_NUM;

	min_dist[base_can_area][goal] = 0;
	Q.push(Info(goal,0));

	while(!Q.empty()){
		if(Q.top().sum_cost > min_dist[base_can_area][Q.top().room_id]){

			Q.pop();

		}else{

			if(Q.top().sum_cost == 0){ //★★猫が自力でゴール可能な範囲のみ、猫扉で移動(猫が可能な限り動いた方が最適)★★

				//猫用エッジ
				for(int i = 0; i < cat_G[Q.top().room_id].size(); i++){
					next_room = cat_G[Q.top().room_id][i];

					if(is_same_group(goal,next_room)){ //猫が自力でゴール可の部屋

						next_cost = Q.top().sum_cost;

					}else{

						next_cost = Q.top().sum_cost+1;
					}

					if(min_dist[base_can_area][next_room] > next_cost){
						min_dist[base_can_area][next_room] = next_cost;
						Q.push(Info(next_room,next_cost));
					}
				}
			}

			//人間用エッジ
			for(int i = 0; i < human_G[Q.top().room_id].size(); i++){

				next_room = human_G[Q.top().room_id][i];

				if(is_same_group(goal,next_room)){ //猫が自力でゴール可の部屋

					next_cost = Q.top().sum_cost;

				}else{

					next_cost = Q.top().sum_cost+1;
				}

				if(min_dist[base_can_area][next_room] > next_cost){
					min_dist[base_can_area][next_room] = next_cost;
					Q.push(Info(next_room,next_cost));
				}
			}
			Q.pop();
		}
	}

	int ans = BIG_NUM;
	for(int i = 0; i <= num_room; i++){
		if(min_dist[base_human][i] == BIG_NUM || min_dist[base_cat][i] == BIG_NUM || min_dist[base_can_area][i] == BIG_NUM)continue;
		ans = min(ans,min_dist[base_human][i]+min_dist[base_cat][i]+min_dist[base_can_area][i]);
	}

	printf("%d\n",ans);
}

int main(){

	int num_case;

	scanf("%d",&num_case);

	goal = 0;

	for(int i = 0; i < num_case; i++){
		func();
	}

	return 0;
}
accuracy: 1
time_ms: 140
memory_kb: 15036
final_rank: 10

code_snippet: #include "bits/stdc++.h"
#include<unordered_map>
#include<unordered_set>
#pragma warning(disable:4996)
using namespace std;


struct UnionFind {
	vector<int> data;
	UnionFind(int size) : data(size, -1) { }
	bool unionSet(int x, int y) {
		x = root(x); y = root(y);
		if (x != y) {
			if (data[y] < data[x]) swap(x, y);
			data[x] += data[y]; data[y] = x;
		}
		return x != y;
	}
	int root(int x) {
		return data[x] < 0 ? x : data[x] = root(data[x]);
	}
	int size(int x) {
		return -data[root(x)];
	}
};

vector<int>diss(const vector<int> goals, const vector<vector<int>>&edges) {
	queue<int>que;
	vector<int>memo(edges.size(),1e8);
	for (auto goal : goals) {
		memo[goal]=0;
		que.push(goal);
	}
	while (!que.empty()) {
		auto now(que.front());
		que.pop();
		for (auto e : edges[now]) {
			if (memo[e] > memo[now] + 1) {
				memo[e]=memo[now]+1;
				que.push(e);
			}
		}
	}
	return memo;
}

int main() {
	int Q;cin>>Q;
	while (Q--) {
		int N,M;cin>>N>>M;
		vector<vector<int>>edges(N+1);
		int natu,reno;cin>>natu>>reno;
		UnionFind uf(N+1);
		for (int i = 0; i < M; ++i) {
			int a,b;char ch;cin>>a>>b>>ch;
			if (ch == 'N') {
				edges[a].push_back(b);
				edges[b].push_back(a);
			}
			else {
				uf.unionSet(a,b);
			}
		}
		vector<int>reno_same;
		vector<int>goal_same;
		for (int i = 0; i <= N; ++i) {
			if(uf.root(i)==uf.root(reno))reno_same.push_back(i);
			if(uf.root(i)==uf.root(0))goal_same.push_back(i);
		}
		auto natu_dis(diss(vector<int>{natu}, edges));
		auto goal_dis(diss(goal_same, edges));
		auto reno_dis(diss(reno_same,edges));

		int ans=1e9;
		for (int i = 0; i <= N; ++i) {
			int sum=natu_dis[i]+goal_dis[i]+reno_dis[i];
			if(ans>sum)ans=sum;
		}
		if(uf.root(reno)==uf.root(0))ans=0;
		cout<<ans<<endl;
	}
	return 0;
}
accuracy: 1
time_ms: 230
memory_kb: 9984
final_rank: 7

code_snippet: #include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <cstring>
#include <vector>
#include <algorithm>
#include <set>
#include <queue>
#include <map>
#include <climits>
#include <complex>
#include <numeric>
using namespace std;

#define REP(i,n) for(int i=0; i<(int)(n); i++)
#define RREP(i,n) for(int i=(int)n-1; i>=0; i--)
#define FOR(i,c) for(__typeof((c).begin())i=(c).begin();i!=(c).end();++i)
#define RFOR(i,c) for(__typeof((c).rbegin())i=(c).rbegin();i!=(c).rend();++i)
#define ALL(c) (c).begin(), (c).end()

typedef long long int ll;
typedef pair<int, int> pii;
typedef pair<int, pair<int, int> > pipii;
typedef vector<int> vi;

const int MOD = 1e9+7;


typedef int Weight;
const Weight INF=99999999;
struct Edge{
    int src,dst;
    Weight weight;
    int rev;
    Edge(int f, int t, Weight c, int rev=0):src(f),dst(t),weight(c),rev(rev){}
    bool operator < (const Edge& re)const{ return weight > re.weight;}
};
typedef vector<vector<Edge> > Graph;
void add_edge(Graph &G, int s, int t, Weight cap){
    G[s].push_back(Edge(s, t, cap, G[t].size()));
}
void shortestPath(const Graph &g, int s, vector<Weight> &dist, vector<int> &prev) {
    int n = g.size();
    dist.assign(n, INF); dist[s] = 0;
    prev.assign(n, -1);
    priority_queue<Edge> Q;
    for(Q.push(Edge(-2, s, 0)); !Q.empty();){
        Edge e = Q.top(); Q.pop();
        if(prev[e.dst] != -1) continue;
        prev[e.dst] = e.src;
        FOR(f,g[e.dst]) {
            if (dist[f->dst] > e.weight+f->weight){
                dist[f->dst] = e.weight+f->weight;
                Q.push(Edge(f->src, f->dst, e.weight+f->weight));
            }
        }
    }
}
void bfs(const Graph &g, int s, vector<Weight> &dist, vector<int> &prev) {
    int n = g.size();
    dist.assign(n, INF); dist[s] = 0;
    prev.assign(n, -1);
    priority_queue<Edge> Q;
    for(Q.push(Edge(-2, s, 0)); !Q.empty();){
        Edge e = Q.top(); Q.pop();
        if(prev[e.dst] != -1) continue;
        prev[e.dst] = e.src;
        FOR(f,g[e.dst]) {
            if(e.weight != 0 && f->weight == 0) continue;
            if (dist[f->dst] > e.weight+f->weight){
                dist[f->dst] = e.weight+f->weight;
                Q.push(Edge(f->src, f->dst, e.weight+f->weight));
            }
        }
    }
}


int main(void){
    int t;
    cin >> t;
    while(t--){
        int n, m;
        cin >> n >> m;
        int natsume, lennon;
        cin >> natsume >> lennon;
        natsume--; lennon--;
        Graph g(n), lg(n), sg(n);
        int summer, tosummer = 0;
        vector<pii> cat;
        REP(i, m){
            int x, y; char c;
            cin >> x >> y >> c;
            x--; y--;

            if(min(x, y) == -1){
                summer = max(x, y);
                if(c == 'N') tosummer = 1; 
                else tosummer = 0;
                continue;
            }

            if(c == 'N'){
                add_edge(g, x ,y, 1);
                add_edge(g, y, x, 1);
                add_edge(lg, x ,y, 1);
                add_edge(lg, y, x, 1);
                add_edge(sg, x ,y, 1);
                add_edge(sg, y, x, 1);
            }else{
                cat.push_back(pii(x, y));
                add_edge(lg, x ,y, 0);
                add_edge(lg, y ,x, 0);
            }
        }
        if(!tosummer){
            FOR(e, cat){
                add_edge(sg, (*e).first, (*e).second, 0); 
                add_edge(sg, (*e).second, (*e).first, 0);
            }
        }
        vi dist_g, dist_lg, dist_sg, prev;
        shortestPath(g, natsume, dist_g, prev);
        prev.clear();
        bfs(lg, lennon, dist_lg, prev);
        prev.clear();
        bfs(sg, summer, dist_sg, prev);
        int ans = INF;
        if(!tosummer && dist_sg[lennon] == 0){
            cout << 0 << endl;
            continue;
        }
        REP(i, n){
            //cout << dist_g[i] << ":" << dist_lg[i] << ":" << dist_sg[i] << endl;
            ans = min(ans, dist_g[i] + dist_lg[i] + dist_sg[i] + tosummer);
        }
        cout << ans << endl;
    }

    return 0;
}
accuracy: 1
time_ms: 600
memory_kb: 25492
final_rank: 19

code_snippet: #include<iostream>
#include<vector>
#include<algorithm>
#include<queue>
#include<set>
#include<map>
#include<cstring>
#include<string>
#include<sstream>
#include<complex>
#include<tuple>

using namespace std;

#define reep(i, s, n) for(int i=s;i<(int)n;i++)
#define rep(i, n) for(int i=0;i<(int)n;i++)
#define REP(i, n) for(int i=0;i<(int)n;i++)
#define all(v) v.begin(), v.end()
#define tyd typedef
#define vc vector
#define pb push_back
#define eb emplace_back
#define mp make_pair

typedef long long ll;
typedef vector<int> vi;
typedef vector<vi> vvi;
typedef pair<int, int> pii;
const int INF = 1<<28;	

int T, n, m, nat, len;

struct UnionFind{
	vector<int> d;
	UnionFind(int n):d(n, -1){}
	bool unite(int x, int y){
		if((x = root(x)) != (y = root(y))){
			if(d[y] < d[x]) swap(x, y);
			d[x] += d[y]; d[y] = x;
		}
		return x != y;
	}
	int root(int x){return d[x] < 0 ? x : d[x] = root(d[x]);}
};

vi bfs(const vector<vi> &g, vi s){
	vi dp(n+1, INF);
	queue<int> q;
	for(int u : s){
		q.push(u);
		dp[u] = 0;
	}
	while(!q.empty()){
		int u = q.front(); q.pop();
		for(int v : g[u])if(dp[u]+1 < dp[v]){
			q.push(v);
			dp[v] = dp[u] + 1;
		}
	}
	return dp;
}


int main(){
	cin >> T;
	while(T--){
		cin >> n >> m >> nat >> len;
		vector<vi> g(n+1);
		UnionFind uf(n+1);
		REP(i, m){
			int u, v; char c;
			cin >> u >> v >> c;
			if(c == 'N'){
				g[u].pb(v);
				g[v].pb(u);
			}else{
				uf.unite(u, v);
			}
		}
		if(uf.root(0) == uf.root(len)){
			puts("0");
			continue;
		}
		vi s1, s2;
		REP(i, n+1) if(uf.root(i) == uf.root(len)) s1.pb(i);
		REP(i, n+1) if(uf.root(i) == uf.root(0)) s2.pb(i);
		auto d1 = bfs(g, s1);
		auto d2 = bfs(g, s2);
		auto d3 = bfs(g, vi({nat}));
		REP(i, n)if(uf.root(i) == 0){
			d1[i] = d1[0];
			d2[i] = d2[0];
			d3[i] = d3[0];
		}
//		cout << "uf: " ;REP(i, n+1) cout << uf.root(i) << ", "; cout << endl;
//		cout << "d1: " ;REP(i, n+1) cout << d1[i] << ", "; cout << endl;
//		cout << "d2: " ; REP(i, n+1) cout << d2[i] << ", "; cout << endl;
//		cout << "d3: " ; REP(i, n+1) cout << d3[i] << ", "; cout << endl;
		int ans = INF;
		REP(i, n) ans = min(ans, d1[i] + d2[i] + d3[i]);
		if(ans < INF) printf("%d\n", ans);
		else puts("-1");
	}
	return 0;
	
}
accuracy: 1
time_ms: 250
memory_kb: 8124
final_rank: 4

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

#define REP(i,s,n) for(int i=s;i<n;i++)
#define rep(i,n) REP(i,0,n)

using namespace std;

struct Edge {
  int dst,weight;
  bool type[2]; // 0 -> hito, 1 -> nyanko
  Edge(int dst=-1,int weight=0,bool a=false,bool b=false) : dst(dst), weight(weight) {
    type[0] = a, type[1] = b;
  }
};

const int MAX_V = 100100;
int V,E,Natsume,Lennon;
vector<Edge> G[MAX_V];
int par[MAX_V],rank[MAX_V];

inline void init(int n=MAX_V){ rep(i,n) par[i] = i, rank[i] = 0; }

int find(int x) {
  if( x == par[x] ) return x;
  return par[x] = find(par[x]);
}

void unit(int x,int y){
  x = find(x), y = find(y);
  if( x != y ) {
    if( rank[x] > rank[y] ) par[y] = x;
    else {
      par[x] = y;
      if( par[x] == par[y] ) ++rank[y];
    }
  }
}

void draw(int sp,int type){
  deque<int> deq;
  deq.push_back(sp);
  while( !deq.empty() ){
    int cur = deq.front(); deq.pop_front();
    rep(i,(int)G[cur].size()){
      int next = G[cur][i].dst;
      if( !G[cur][i].type[type] ) continue;
      if( find(cur) != find(next) ) {
        unit(cur,next);
        deq.push_back(next);
      }
    }
  }
}

const int IINF = INT_MAX;
int mindist[3][MAX_V]; // 0-> Natsume, 1-> Summer, 2-> Lennon

void calc(int stype,vector<int> &sp){
  rep(i,V) mindist[stype][i] = IINF;
  deque<int> deq;
  rep(i,sp.size()) {
    mindist[stype][sp[i]] = 0;
    deq.push_back(sp[i]);
  }
  while( !deq.empty() ){
    int cur = deq.front(); deq.pop_front();
    rep(i,G[cur].size()){
      int next = G[cur][i].dst;
      if( !G[cur][i].type[0] ) continue;
      if( mindist[stype][next] > mindist[stype][cur] + 1 ){
        mindist[stype][next] = mindist[stype][cur] + 1;
        deq.push_back(next);
      }
    }
  }
}

void compute(){
  draw(0,1);
  draw(Lennon,1);
  if( find(0) == find(Lennon) ) { puts("0"); return; }
  vector<int> sp;
  sp.push_back(Natsume);
  calc(0,sp);
  sp.clear();

  rep(i,V) if( find(0) == find(i) ) sp.push_back(i);
  calc(1,sp);
  sp.clear();

  rep(i,V) if( find(Lennon) == find(i) ) sp.push_back(i);
  calc(2,sp);
  
  int mini = IINF;
  rep(i,V) if( mindist[0][i] != IINF && mindist[1][i] != IINF && mindist[2][i] != IINF ) {
    mini = min(mini,mindist[0][i]+mindist[1][i]+mindist[2][i]);
  }

  cout << mini << endl;

}

int main(int argc,char** argv){
  int T;
  cin >> T;
  while( T-- ) {
    cin >> V >> E;
    cin >> Natsume >> Lennon;
    ++V;
    rep(i,V) G[i].clear();
    init(V);
    rep(_,E){
      int s,t;
      char c;
      cin >> s >> t >> c;
      if( c == 'N' ) {
        G[s].push_back(Edge(t,1,true,false));
        G[t].push_back(Edge(s,1,true,false));
      } else {
        G[s].push_back(Edge(t,0,false,true));
        G[t].push_back(Edge(s,0,false,true));
      }
    }
    compute();
  }
  return 0;
}
accuracy: 1
time_ms: 280
memory_kb: 12768
final_rank: 15

code_snippet: #include <bits/stdc++.h>
using namespace std;
 
struct Edge {
  int v, w;
};
 
typedef vector<vector<Edge> > Graph;
typedef pair<int, int> Pair;
 
const int INF = 1<<28;
 
int n, m, N, L;
Graph g;
 
vector<int> dijkstra(int src, int scost) {
  vector<int> cost(n, INF);
  priority_queue<Pair, vector<Pair>, greater<Pair> > que;
  cost[src] = scost;
  que.push(Pair(scost, src));
  while(que.size()) {
    const Pair s = que.top(); que.pop();
    if(cost[s.second] < s.first) continue;
    for(int i = 0; i < g[s.second].size(); ++i) {
      const Edge &e = g[s.second][i];
      if(s.first && !e.w) continue; //
      const Pair t(s.first + e.w, e.v);
      if(cost[t.second] <= t.first) continue;
      cost[t.second] = t.first;
      que.push(t);
    }
  }
  return cost;
}
 
struct State {
  int v, f, cost;
  bool operator < (const State &s) const {
    return cost > s.cost;
  }
};
 
int main() {
  int T; cin >> T;
  while(T--) {
    cin >> n >> m;
    ++n;
    cin >> N >> L;
    g = Graph(n);
    for(int i = 0; i < m; ++i) {
      int a, b; char c;
      cin >> a >> b >> c;
      g[a].push_back((Edge){b, c == 'N'});
      g[b].push_back((Edge){a, c == 'N'});
    }
    vector<int> fromN = dijkstra(N, 1);
    vector<int> fromL = dijkstra(L, 0);
    vector<int> fromS = dijkstra(0, 0);
    if(fromL[0] == 0) {
      cout << 0 << endl;
      continue;
    }
    int res = INF;
    for(int i = 0; i < n; ++i) {
      res = min(res, fromN[i] + fromL[i] + fromS[i] - 1);
    }
    cout << res << endl;
  }
  return 0;
}
accuracy: 1
time_ms: 370
memory_kb: 9096
final_rank: 14

code_snippet: #include <iostream>
#include <complex>
#include <sstream>
#include <string>
#include <algorithm>
#include <deque>
#include <list>
#include <map>
#include <numeric>
#include <queue>
#include <vector>
#include <set>
#include <limits>
#include <cstdio>
#include <cctype>
#include <cmath>
#include <cstring>
#include <cstdlib>
#include <ctime>
using namespace std;
#define REP(i, j) for(int i = 0; i < (int)(j); ++i)
#define FOR(i, j, k) for(int i = (int)(j); i < (int)(k); ++i)
#define SORT(v) sort((v).begin(), (v).end())
#define REVERSE(v) reverse((v).begin(), (v).end())
typedef pair<int, int> P;
const int INF = 1e9;

int N, M, hs, cs;

void dfs(int n, set<int> &S, vector< vector<int> > &es){
  S.insert(n);
  for(int next : es[n]) if(S.find(next) == S.end()) dfs(next, S, es);
}

void bfs(vector< vector<int> > &es, queue<int> &open, vector<int> &closed){
  while(!open.empty()){
    int now = open.front(), cost = closed[now]; open.pop();
    for(int next : es[now]){
      if(closed[next] > cost + 1){
        closed[next] = cost + 1;
        open.push(next);
      }
    }
  }
}

int main() {
  int T; cin >>T;
  while(T--){
    cin >>N >>M >>hs >>cs;
    N++;
    vector< vector<int> > hes(N), ces(N);
    REP(i, M){
      int a, b; char c; cin >>a >>b >>c;
      if(c == 'N') { hes[a].push_back(b); hes[b].push_back(a); }
      else { ces[a].push_back(b); ces[b].push_back(a); }
    }

    set<int> X, Y;
    dfs(cs, X, ces); dfs(0, Y, ces);
    if(X == Y) { cout <<0 <<endl; continue; }

    vector<int> A, B, C, ac(N, INF), bc(N, INF), cc(N, INF);
    queue<int> aq, bq, cq;
    aq.push(hs); ac[hs] = 0;
    for(int n : X) { bq.push(n); bc[n] = 0; }
    for(int n : Y) { cq.push(n); cc[n] = 0; }
    bfs(hes, aq, ac);
    bfs(hes, bq, bc);
    bfs(hes, cq, cc);

    int ans = INF;
    REP(i, N) ans = min(ans, ac[i] + bc[i] + cc[i]);
    cout <<ans <<endl;
  }
  return 0;
}
accuracy: 1
time_ms: 290
memory_kb: 10168
final_rank: 11

code_snippet: #include<stdio.h>
#include<algorithm>
#include<queue>
#include<vector>
using namespace std;
vector<int> g[110000];
vector<int> g2[110000];
char in[4];
int v1[110000];
int v2[110000];
int A[110000];
int B[110000];
int C[110000];
int main(){
	int T;scanf("%d",&T);
	while(T--){
		int a,b;scanf("%d%d",&a,&b);
		int c,d;scanf("%d%d",&c,&d);
		for(int i=0;i<a+1;i++)g[i].clear();
		for(int i=0;i<a+1;i++)g2[i].clear();
		for(int i=0;i<b;i++){
			int p,q;scanf("%d%d%s",&p,&q,in);
			if(in[0]=='N'){
				g[p].push_back(q);
				g[q].push_back(p);
			}else{
				g2[p].push_back(q);
				g2[q].push_back(p);
			}
		}
		for(int i=0;i<a+1;i++)v1[i]=v2[i]=0;
		queue<int>Q;
		Q.push(0);
		v1[0]=1;
		while(Q.size()){
			int at=Q.front();Q.pop();
			for(int i=0;i<g2[at].size();i++)if(!v1[g2[at][i]]){
				v1[g2[at][i]]=1;
				Q.push(g2[at][i]);
			}
		}
		v2[d]=1;
		Q.push(d);
		while(Q.size()){
			int at=Q.front();Q.pop();
			for(int i=0;i<g2[at].size();i++)if(!v2[g2[at][i]]){
				v2[g2[at][i]]=1;
				Q.push(g2[at][i]);
			}
		}
		if(v1[d]){
			printf("0\n");continue;
		}
		for(int i=0;i<a+1;i++)A[i]=B[i]=C[i]=99999999;
		A[c]=0;
		Q.push(c);
		while(Q.size()){
			int at=Q.front();Q.pop();
			for(int i=0;i<g[at].size();i++){
				if(A[g[at][i]]>9999999){
					A[g[at][i]]=A[at]+1;
					Q.push(g[at][i]);
				}
			}
		}
		for(int i=0;i<a+1;i++)if(v1[i]){
			Q.push(i);
			B[i]=0;
		}
		while(Q.size()){
			int at=Q.front();Q.pop();
			for(int i=0;i<g[at].size();i++){
				if(B[g[at][i]]>9999999){
					B[g[at][i]]=B[at]+1;
					Q.push(g[at][i]);
				}
			}
		}
		for(int i=0;i<a+1;i++)if(v2[i]){
			Q.push(i);
			C[i]=0;
		}
		while(Q.size()){
			int at=Q.front();Q.pop();
			for(int i=0;i<g[at].size();i++){
				if(C[g[at][i]]>9999999){
					C[g[at][i]]=C[at]+1;
					Q.push(g[at][i]);
				}
			}
		}
		int ret=999999999;
		for(int i=0;i<a+1;i++)ret=min(ret,A[i]+B[i]+C[i]);
		printf("%d\n",ret);
	}
}
accuracy: 1
time_ms: 140
memory_kb: 13312
final_rank: 8

code_snippet: #include<cstdio>
#include<vector>

#define rep(i,n) for(int i=0;i<(n);i++)

using namespace std;

const int INF=1<<29;

class union_find{
	vector<int> a;
public:
	union_find(int n):a(n,-1){}
	int find(int x){
		if(a[x]<0) return x;
		return a[x]=find(a[x]);
	}
	void unite(int x,int y){
		x=find(x),y=find(y);
		if(x!=y){ a[x]+=a[y]; a[y]=x; }
	}
};

int main(){
	int T; scanf("%d",&T);
	while(T--){
		int n,m,natsume,renon; scanf("%d%d%d%d",&n,&m,&natsume,&renon);

		static vector<int> G[100001]; // Natsume graph
		rep(u,n+1) G[u].clear();

		union_find U(n+1);
		rep(i,m){
			int u,v;
			char c; scanf("%d%d %c",&u,&v,&c);
			if(c=='N'){
				G[u].push_back(v);
				G[v].push_back(u);
			}
			else U.unite(u,v);
		}

		if(U.find(renon)==U.find(0)){ puts("0"); continue; }

		static int d1[100001]; // d1[u] := dist(Natsume,u)
		rep(u,n+1) d1[u]=INF;
		{
			int head=0,tail=0;
			static int Q[100001];
			d1[natsume]=0;
			Q[tail++]=natsume;
			while(head<tail){
				int u=Q[head++];
				rep(i,G[u].size()){
					int v=G[u][i];
					if(d1[v]==INF) d1[v]=d1[u]+1, Q[tail++]=v;
				}
			}
		}

		static int d2[100001]; // d2[u] := dist(Renon,u)
		rep(u,n+1) d2[u]=INF;
		{
			int head=0,tail=0;
			static int Q[100001];
			rep(u,n+1) if(U.find(u)==U.find(renon)) d2[u]=0, Q[tail++]=u;
			while(head<tail){
				int u=Q[head++];
				rep(i,G[u].size()){
					int v=G[u][i];
					if(d2[v]==INF) d2[v]=d2[u]+1, Q[tail++]=v;
				}
			}
		}

		static int d3[100001]; // d3[u] := dist(summer,u)
		rep(u,n+1) d3[u]=INF;
		{
			int head=0,tail=0;
			static int Q[100001];
			rep(u,n+1) if(U.find(u)==U.find(0)) d3[u]=0, Q[tail++]=u;
			while(head<tail){
				int u=Q[head++];
				rep(i,G[u].size()){
					int v=G[u][i];
					if(d3[v]==INF) d3[v]=d3[u]+1, Q[tail++]=v;
				}
			}
		}

		int ans=INF;
		rep(u,n+1) ans=min(ans,d1[u]+d2[u]+d3[u]);
		printf("%d\n",ans);
	}

	return 0;
}
accuracy: 1
time_ms: 130
memory_kb: 9516
final_rank: 3

code_snippet: #include <cstdio>
#include <iostream>
#include <sstream>
#include <iomanip>
#include <algorithm>
#include <cmath>
#include <string>
#include <vector>
#include <list>
#include <queue>
#include <stack>
#include <set>
#include <map>
#include <bitset>
#include <numeric>
#include <climits>
#include <cfloat>
using namespace std;

const int INF = INT_MAX / 4;

void catMove(const vector<vector<int> >& edges, int start, vector<bool>& move)
{
    int n = edges.size();
    move.assign(n, false);
    move[start] = true;
    queue<int> q;
    q.push(start);

    while(!q.empty()){
        int s = q.front();
        q.pop();
        for(unsigned i=0; i<edges[s].size(); ++i){
            int t = edges[s][i];
            if(!move[t]){
                move[t] = true;
                q.push(t);
            }
        }
    }
}

void humanMove(const vector<vector<int> >& edges, const vector<bool>& start, vector<int>& cost)
{
    int n = edges.size();
    cost.assign(n, INF);
    queue<int> q;
    for(int i=0; i<n; ++i){
        if(start[i]){
            cost[i] = 0;
            q.push(i);
        }
    }

    while(!q.empty()){
        int s = q.front();
        q.pop();
        for(unsigned i=0; i<edges[s].size(); ++i){
            int t = edges[s][i];
            if(cost[t] == INF){
                cost[t] = cost[s] + 1;
                q.push(t);
            }
        }
    }
}

int main()
{
    int d;
    cin >> d;

    while(--d >= 0){
        int n, m, sh, sc;
        cin >> n >> m >> sh >> sc;

        vector<vector<int> > edgesH(n+1), edgesC(n+1);
        for(int i=0; i<m; ++i){
            int a, b;
            char c;
            cin >> a >> b >> c;

            if(c == 'N'){
                edgesH[a].push_back(b);
                edgesH[b].push_back(a);
            }else{
                edgesC[a].push_back(b);
                edgesC[b].push_back(a);
            }
        }

        vector<bool> move1, move2;
        catMove(edgesC, 0, move1);
        catMove(edgesC, sc, move2);

        vector<bool> move3(n+1);
        move3[sh] = true;

        if(move1[sc]){
            cout << 0 << endl;
            continue;
        }

        vector<int> cost1, cost2, cost3;
        humanMove(edgesH, move1, cost1);
        humanMove(edgesH, move2, cost2);
        humanMove(edgesH, move3, cost3);

        int ret = INF;
        for(int i=0; i<=n; ++i)
            ret = min(ret, cost1[i] + cost2[i] + cost3[i]);
        cout << ret << endl;
    }

    return 0;
}
accuracy: 1
time_ms: 320
memory_kb: 10244
final_rank: 13

code_snippet: #include <iostream>
#include <iomanip>
#include <sstream>
#include <cstdio>
#include <string>
#include <vector>
#include <algorithm>
#include <complex>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <cassert>
#include <climits>
#include <queue>
#include <set>
#include <map>
#include <valarray>
#include <bitset>
#include <stack>
using namespace std;

#define REP(i,n) for(int i=0;i<(int)n;++i)
#define FOR(i,c) for(__typeof((c).begin())i=(c).begin();i!=(c).end();++i)
#define ALL(c) (c).begin(), (c).end()
typedef long long ll;
typedef pair<int,int> pii;
const int INF = 1<<29;
const double PI = acos(-1);
const double EPS = 1e-8;

struct Edge {
  int dst;
  char c;
};

typedef vector<vector<Edge> > G;
const int N = 100005;
bool visited[N];

void bfs(const G &g, int s, vector<int> &v) {
  int n = g.size();
  REP(i,n) visited[i] = 0;
  queue<int> Q; Q.push(s);
  visited[s] = 1;
  while(!Q.empty()) {
    int now = Q.front(); Q.pop();
    v.push_back(now);
    FOR(it, g[now]) {
      if (it->c == 'N') continue;
      int dst = it->dst;
      if (!visited[dst]) {
        visited[dst] = 1;
        Q.push(dst);
      }
    }
  }
}

void bfs2(const G &g, const vector<int> &v, int *dist) {
  int n = g.size();
  REP(i,n) dist[i] = INF;
  queue<int> Q;
  FOR(it, v) {
    Q.push(*it);
    dist[*it] = 0;
  }
  while(!Q.empty()) {
    int now = Q.front(); Q.pop();
    FOR(it, g[now]) {
      if (it->c == 'L') continue;
      int dst = it->dst;
      if (dist[dst] == INF) {
        dist[dst] = dist[now] + 1;
        Q.push(dst);
      }
    }
  }
}

int dist1[N];
int dist2[N];
int dist3[N];

int main() {
  int T;
  cin >> T;
  while(T--) {
    int n, m;
    cin >> n >> m;
    int ns, ls;
    cin >> ns >> ls;
    G g(n+1);
    REP(i,m) {
      char c;
      int a,b;
      cin >> a >> b >> c;
      g[a].push_back((Edge){b,c});
      g[b].push_back((Edge){a,c});
    }
    vector<int> vA;             // レノンがいる場所から自由にいける場所
    vector<int> vB;             // 夏への扉から自由にいける場所
    bfs(g,ls,vA);
    bfs(g,0,vB);
    if (find(ALL(vA),0) != vA.end()) {
      cout << 0 << endl;
      continue;
    }
    bfs2(g,vA,dist1);
    bfs2(g,vB,dist2);
    bfs2(g,vector<int>(1,ns),dist3);
    int ans = INF;
    REP(i,n+1) {
      //cout << dist1[i] << " " << dist2[i] << " " << dist3[i] << endl;
      ans = min(ans, dist1[i]+dist2[i]+dist3[i]);
    }
    cout << ans << endl;
  }
}
accuracy: 1
time_ms: 560
memory_kb: 5972
final_rank: 16

code_snippet: #include <stdio.h>
#include <string.h>
#include <algorithm>
#include <iostream>
#include <math.h>
#include <assert.h>
#include <vector>
#include <queue>
#include <string>
#include <map>
#include <set>

using namespace std;
typedef long long ll;
typedef unsigned int uint;
typedef unsigned long long ull;
static const double EPS = 1e-9;
static const double PI = acos(-1.0);

#define REP(i, n) for (int i = 0; i < (int)(n); i++)
#define FOR(i, s, n) for (int i = (s); i < (int)(n); i++)
#define FOREQ(i, s, n) for (int i = (s); i <= (int)(n); i++)
#define FORIT(it, c) for (__typeof((c).begin())it = (c).begin(); it != (c).end(); it++)
#define MEMSET(v, h) memset((v), h, sizeof(v))

typedef vector<int> Edges;
typedef vector<Edges> Graph;

struct Node {
  int state;
  int from;
  int cost;
  Node(int state, int from, int cost) :
    state(state), from(from), cost(cost) {;}
  bool operator<(const Node &rhs) const {
    return cost > rhs.cost;
  }
};

int natume;
int lennon;
int n, m;
Graph mainG;
Graph nekoG;
bool end[100010];
int dist[100010];
bool visit[2][100010];

int main() {
  int test;
  scanf("%d", &test);
  while (test--) {
    MEMSET(dist, 0x0f);
    MEMSET(end, false);
    scanf("%d %d", &n, &m);
    scanf("%d %d", &natume, &lennon);
    mainG = Graph(n + 1);
    nekoG = Graph(n + 1);
    REP(i, m) {
      int f, t;
      char c;
      scanf("%d %d %c", &f, &t, &c);
      if (c == 'N') {
        mainG[f].push_back(t);
        mainG[t].push_back(f);
      } else {
        nekoG[f].push_back(t);
        nekoG[t].push_back(f);
      }
    }

    // clac end
    {
      queue<int> que;
      que.push(lennon);
      end[lennon] = true;
      while (!que.empty()) {
        int from = que.front();
        que.pop();
        FORIT(it, nekoG[from]) {
          int to = *it;
          if (end[to]) { continue; }
          end[to] = true;
          que.push(to);
        }
      }
    }
    if (end[0]) {
      puts("0");
      continue;
    }

    // calc dist
    {
      queue<pair<int, int> > que;
      que.push(make_pair(natume, 0));
      MEMSET(visit, false);
      while (!que.empty()) {
        int from = que.front().first;
        int cost = que.front().second;
        que.pop();
        if (visit[0][from]) { continue; }
        visit[0][from] = true;
        dist[from] = cost;
        FORIT(it, mainG[from]) {
          int to = *it;
          if (visit[0][to]) { continue; }
          que.push(make_pair(to, cost + 1));
        }
      }
    }


    priority_queue<Node> pque;
    // push pque
    {
      queue<int> que;
      que.push(0);
      MEMSET(visit, false);
      visit[0][0] = true;
      while (!que.empty()) {
        int from = que.front();
        que.pop();
        pque.push(Node(0, from, 0));
        FORIT(it, nekoG[from]) {
          int to = *it;
          if (visit[0][to]) { continue; }
          visit[0][to] = true;
          que.push(to);
        }
      }
    }

    // calc ans
    MEMSET(visit, false);
    while (!pque.empty()) {
      int state = pque.top().state;
      int from = pque.top().from;
      int cost = pque.top().cost;
      pque.pop();
      if (visit[state][from]) { continue; }
      visit[state][from] = true;
      if (state == 1 && end[from]) {
        printf("%d\n", cost);
        break;
      }
      FORIT(it, mainG[from]) {
        int to = *it;
        if (visit[state][to]) { continue; }
        int ncost = cost + 1;
        pque.push(Node(state, to, ncost));
      }
      if (state == 0) {
        pque.push(Node(1, from, cost + dist[from]));
      }
    }
  }
}
accuracy: 1
time_ms: 320
memory_kb: 7584
final_rank: 9

code_snippet: #include<iostream>
#include<algorithm>
#include<vector>
#include<stack>
#include<map>
#include<set>
#include<queue>
#include<cstdio>
#include<climits>
#include<cmath>
#include<cstring>
#include<string>
#include<sstream>
#include<numeric>
#include<cassert>

#define f first
#define s second
#define mp make_pair

#define REP(i,n) for(int i=0; i<(int)(n); i++)
#define rep(i,s,n) for(int i=(s); i<(int)(n); i++)
#define FOR(i,c) for(__typeof((c).begin()) i=(c).begin(); i!=(c).end(); i++)
#define ALL(c) (c).begin(), (c).end()
#define IN(x,s,g) ((x) >= (s) && (x) < (g))
#define ISIN(x,y,w,h) (IN((x),0,(w)) && IN((y),0,(h)))
#define print(x) printf("%d\n",x)

using namespace std;

typedef unsigned int uint;
typedef long long ll;

const int _dx[] = {0,1,0,-1};
const int _dy[] = {-1,0,1,0};

int getInt(){
  int ret = 0,c;
  c = getchar();
  while(!isdigit(c)) c = getchar();
  while(isdigit(c)){
    ret *= 10;
    ret += c - '0';
    c = getchar();
  }
  return ret;
}

int nmemo[100001];
int nlmemo[100001];
int nsmemo[100001];
int lmemo[100001];
int smemo[100001];

void make_memo(const vector<vector<int> > &door, int *memo, const vector<int> &start){
  queue<int> q;
  FOR(it, start){ memo[*it] = 0; q.push(*it); }
  while(q.size()){
    int pos = q.front(); q.pop(); int cnt = memo[pos];
    FOR(it, door[pos]) if(memo[*it] == -1){
      memo[*it] = cnt + 1; q.push(*it);
    }
  }
}

int main(){
  int c; scanf("%d", &c);
  while(c --> 0){
    int n, m;
    scanf("%d%d", &n, &m);
    
    int natsume, lenon;
    scanf("%d%d", &natsume, &lenon);

    vector<vector<int> > ndoor(n+1);
    vector<vector<int> > ldoor(n+1);

    REP(i, m){
      int a, b; char p;
      scanf("%d%d %c", &a, &b, &p);
      if(p == 'N'){
	ndoor[a].push_back(b);
	ndoor[b].push_back(a);
      }else{
	ldoor[a].push_back(b);
	ldoor[b].push_back(a);
      }
    }

    REP(i, n+1) nsmemo[i] = nlmemo[i] = nmemo[i] = lmemo[i] = smemo[i] = -1;

    make_memo(ndoor, nmemo, vector<int>(1, natsume));
    make_memo(ldoor, lmemo, vector<int>(1, lenon));
    make_memo(ldoor, smemo, vector<int>(1, 0));

    if(lmemo[0] != -1){
      print(0);
    }else{
      vector<int> l; REP(i, n+1) if(lmemo[i] != -1) l.push_back(i);
      vector<int> s; REP(i, n+1) if(smemo[i] != -1) s.push_back(i);
      make_memo(ndoor, nlmemo, l);
      make_memo(ndoor, nsmemo, s);
      
      int ans = INT_MAX;
      REP(i, n+1) if(nmemo[i] != -1 && nsmemo[i] != -1 && nlmemo[i] != -1)
	ans = min(ans, nmemo[i] + nsmemo[i] + nlmemo[i]);
      
      print(ans);
    }
  }
  
  return 0;
}
accuracy: 1
time_ms: 320
memory_kb: 7052
final_rank: 6

code_snippet: #include <iostream>
#include <queue>
#include <vector>
#include <string>
#include <set>
using namespace std;

vector<vector<int> > h_edges, c_edges;

void dfs1(set<int> &ss,int start) {
    queue<int> q; q.push(start); ss.insert(start);
    while(!q.empty()) {
        int ns = q.front(); q.pop();
        for(int i=0; i<c_edges[ns].size(); ++i)
            if(ss.find(c_edges[ns][i]) == ss.end()) {
                q.push(c_edges[ns][i]);
                ss.insert(c_edges[ns][i]);
            }
    }
}

void bfs(queue<int> &q,vector<int> &dist) {
    while(!q.empty()) {
        int ns = q.front(); q.pop();
        for(int i=0; i<h_edges[ns].size(); ++i) {
            if(dist[h_edges[ns][i]] > dist[ns]+1) {
                dist[h_edges[ns][i]] = dist[ns]+1;
                q.push(h_edges[ns][i]);
            }
        }
    }
}

int main() {
    int n,m,tc,a,b,h_start,c_start;
    string s;
    cin>>tc;

    while(tc--) {
        cin>>n>>m;
        cin>>h_start>>c_start;
        h_edges.clear(); c_edges.clear();
        h_edges.resize(n+1); c_edges.resize(n+1);

        for(int i=0; i<m; ++i) {
            cin>>a>>b>>s;
            if(s == "N") {
                h_edges[a].push_back(b);
                h_edges[b].push_back(a);
            }else{
                c_edges[a].push_back(b);
                c_edges[b].push_back(a);
            }
        }

        set<int> canReach,fromGoal;
        // dfs1
        dfs1(canReach, c_start);
        dfs1(fromGoal, 0);

        if(canReach.find(0) != canReach.end()) {
            cout<<0<<endl;
            continue;
        }

        queue<int> q;
        vector<int> d1(n+1,1<<29), d2(n+1, 1<<29), d3(n+1, 1<<29);
        d1[h_start] = 0; q.push(h_start);
        bfs(q,d1);

//        cout<<canReach.size()<<endl;
        for(set<int>::iterator it = canReach.begin();
            it != canReach.end(); ++it) {
            q.push(*it); d2[*it] = 0;
        }
        bfs(q,d2);

        for(set<int>::iterator it = fromGoal.begin();
            it != fromGoal.end(); ++it) {
            q.push(*it); d3[*it] = 0;
        }
        bfs(q,d3);

        int ans = 1<<29;
        for(int i=0; i<=n; ++i) {
//            cout<<i<<" -> "<<d1[i]<<","<<d2[i]<<","<<d3[i]<<endl;
            ans = min(ans, d1[i]+d2[i]+d3[i]);
        }
        cout<<ans<<endl;
    }
}
accuracy: 1
time_ms: 650
memory_kb: 7440
final_rank: 17

code_snippet: #include<iostream>
#include<algorithm>
#include<vector>
#include<queue>
using namespace std;
#define REP(i,b,n) for(int i=b;i<n;i++)
#define rep(i,n)   REP(i,0,n)
#define pb         push_back
const int N = 100005;
const int inf = ( 1 << 21);


class Edge{
public:
  int next,c;
};

class state{
public:
  int now,c;
  bool operator<(const state & a)const{
    return c > a.c;
  }
};

void dijkstra(vector<int>&ini,int n,vector<Edge> *edge,int *cost){
  rep(i,n)cost[i]=inf;
  
  priority_queue<state>  Q;
  rep(i,ini.size()){
    Q.push((state){ini[i],0});
  }
  
  while(!Q.empty()){
    state now = Q.top();Q.pop();
    if (cost[now.now] != inf)continue;
    cost[now.now]=now.c;
    rep(i,edge[now.now].size()){
      int next=edge[now.now][i].next,nec=now.c+edge[now.now][i].c;
      Q.push((state){next,nec});
    }
  }
}

vector<Edge> Ledge[N],Nedge[N];
int Lcost[N],Scost[N],Ncost[N];
int LBFS[N],SBFS[N];

template<class T> void op(T &in,int n){rep(i,n)cout<<in[i]<<' ';cout << endl;}

int solve(int n,int L,int S,int N){
  vector<int> ini;
  ini.push_back(L);
  dijkstra(ini,n,Ledge,LBFS);
  //  op(LBFS,n);
  if (LBFS[S] != inf)return 0;//natune is not needed
  ini.clear();

  

  ini.push_back(S);
  dijkstra(ini,n,Ledge,SBFS);
  ini.clear();

  //  op(SBFS,n);


  vector<int> Lini,Nini,Sini;
  Nini.push_back(N);
  rep(i,n){
    if (LBFS[i] != inf)Lini.push_back(i);
    if (SBFS[i] != inf)Sini.push_back(i);
  }

  dijkstra(Lini,n,Nedge,Lcost);
  dijkstra(Sini,n,Nedge,Scost);
  dijkstra(Nini,n,Nedge,Ncost);

  
  int ans = inf;
  rep(i,n){
    //if (LBFS[i] == inf && SBFS[i] == inf)
      ans=min(ans,Ncost[i]+Scost[i]+Lcost[i]);
  }
  return ans;
}


main(){
  int te;
  cin>>te;
  while(te--){
    int n,m;
    cin>>n >>m;
    n++;
    rep(i,n)Nedge[i].clear(),Ledge[i].clear();
    int S = 0,L,N;
    cin>>N>>L;

    rep(i,m){
      int f,t;
      char k;
      cin>>f>>t>>k;
      if (k == 'L'){
	Ledge[f].pb((Edge){t,1});
	Ledge[t].pb((Edge){f,1});
      }else if (k == 'N'){
	Nedge[f].pb((Edge){t,1});
	Nedge[t].pb((Edge){f,1});
      }
    }
    cout << solve(n,L,S,N) << endl;
  }
}
accuracy: 1
time_ms: 670
memory_kb: 10000
final_rank: 18