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


#define NUM 600


struct Edge{
	Edge(int arg_to,bool arg_is_same){
		to = arg_to;
		is_same = arg_is_same;
	}
	int to;
	bool is_same;
};

int N,P1,P2;
int member_num[NUM][2];
int boss[NUM],height[NUM];
int dp[NUM][301],which_assign[NUM][301];
int group_id,group_boss_id[NUM];
bool visited[NUM];
vector<int> WHICH[NUM][2],ANS;
vector<Edge> G[NUM];

//自分のボスのindexを取得しつつ、経路圧縮を行う関数
int get_boss(int id){
	if(boss[id] == id)return id; //自分が代表なら、自分の値を返す
	else{
		return boss[id] = get_boss(boss[id]); //代表でないなら、自分が所属する組織の代表を返しつつ、経路圧縮
	}
}

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 divide_group(int node_id,int group_id,int color){

	visited[node_id] = true;
	WHICH[group_id][color].push_back(node_id); //メンバーのIDをpush
	member_num[group_id][color]++; //メンバーの数をpush

	for(int i = 0; i < G[node_id].size(); i++){
		if(visited[G[node_id][i].to])continue;

		if(G[node_id][i].is_same){ //同じ種族
			divide_group(G[node_id][i].to,group_id,color);
		}else{ //別の種族
			divide_group(G[node_id][i].to,group_id,1-color);
		}
	}
}

void func(){

	for(int i = 0; i < P1+P2; i++){
		G[i].clear();
		for(int k = 0; k < 2; k++){
			WHICH[i][k].clear();
			member_num[i][k] = 0;
		}
		boss[i] = i;
		height[i] = 0;
		visited[i] = false;
	}

	int from,to;
	char buf[4];

	for(int loop = 0; loop < N; loop++){

		scanf("%d %d %s",&from,&to,buf);
		from--;
		to--;
		unite(from,to);

		if(buf[0] == 'y'){ //同じグループ
			G[from].push_back(Edge(to,true));
			G[to].push_back(Edge(from,true));
		}else{ //違うグループ
			G[from].push_back(Edge(to,false));
			G[to].push_back(Edge(from,false));
		}
	}

	group_id = 0;
	//各連結成分を、2つのグループに分ける
	for(int i = 0; i < P1+P2; i++){
		if(visited[i])continue;

		int boss_id = get_boss(i);
		group_boss_id[group_id] = boss_id;

		divide_group(i,group_id,0);
		group_id++;
	}

	for(int i = 0; i <= group_id; i++){
		for(int k = 0; k <= P1; k++){
			dp[i][k] = 0; //dp[何番目のグループまで見たか][種族divineの人数] = 場合の数
			which_assign[i][k] = 0; //復元用<0と1,どちらのグループを採用したか>
		}
	}

	dp[0][member_num[0][0]]++;
	which_assign[0][member_num[0][0]] = 0;

	dp[0][member_num[0][1]]++;
	which_assign[0][member_num[0][1]] = 1;

	for(int i = 1; i < group_id; i++){
		for(int k = 0; k <= P1; k++){
			if(dp[i-1][k] == 0)continue;

			//0番目のグループをdivineと見なした場合
			if(k+member_num[i][0] <= P1){
				dp[i][k+member_num[i][0]]++;
				which_assign[i][k+member_num[i][0]] = 0;
			}
			//1番目のグループをdivineと見なした場合
			if(k+member_num[i][1] <= P1){
				dp[i][k+member_num[i][1]]++;
				which_assign[i][k+member_num[i][1]] = 1;
			}
		}
	}

	if(dp[group_id-1][P1] != 1){ //解が1意に定まらない場合
		printf("no\n");
		return;
	}

	//dpを逆回しして、メンバーを特定する
	ANS.clear();
	int num = P1;

	for(int i = group_id-1; i >= 0; i--){

		for(int k = 0; k < WHICH[i][which_assign[i][num]].size(); k++){
			ANS.push_back(WHICH[i][which_assign[i][num]][k]);
		}
		num -= member_num[i][which_assign[i][num]]; //★★割り当てた人数を引けば、dpを遡れる★★
	}

	sort(ANS.begin(),ANS.end());

	for(int i = 0; i < ANS.size(); i++){
		printf("%d\n",ANS[i]+1);
	}
	printf("end\n");
}


int main(){

	while(true){
		scanf("%d %d %d",&N,&P1,&P2);
		if(N == 0 && P1 == 0 && P2 == 0)break;


		func();
	}

	return 0;
}

