#include<set>
#include<cstdio>
#include<vector>
#include<cstring>
#include<algorithm>

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

using namespace std;

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 size(int x){ return -a[find(x)]; }
};

int main(){
	for(int m,n1,n2;scanf("%d%d%d",&m,&n1,&n2),m+n1+n2;){
		int n=n1+n2;
		vector< pair<int,int> > yes,no;
		rep(i,m){
			int u,v;
			char s[4]; scanf("%d%d%s",&u,&v,s); u--; v--;
			if(s[0]=='y'){
				yes.push_back(make_pair(u,v));
			}
			else{
				no.push_back(make_pair(u,v));
			}
		}

		// yes でつながる人は同じグループ
		union_find U(n);
		rep(i,yes.size()){
			int u=yes[i].first,v=yes[i].second;
			U.unite(u,v);
		}

		int N=0,id[600],sz[600];
		{
			bool used[600]={};
			rep(u,n) if(!used[U.find(u)]) {
				used[U.find(u)]=true;
				id[U.find(u)]=N;
				sz[N++]=U.size(u);
			}
		}

		// no でつながる人は違うグループ
		vector<int> G[600];
		{
			set< pair<int,int> > used;
			rep(i,no.size()){
				int u=id[U.find(no[i].first)],v=id[U.find(no[i].second)];
				if(u>v) swap(u,v);
				if(used.count(make_pair(u,v))==0){
					used.insert(make_pair(u,v));
					G[u].push_back(v);
					G[v].push_back(u);
				}
			}
		}

		vector< pair<int,int> > num; // G の各連結成分に含まれる左の頂点, 右の頂点の個数
		vector< pair< vector<int>,vector<int> > > vs; // 具体的な頂点集合
		bool vis[600]={};
		rep(u,N) if(!vis[u]) {
			vis[u]=true;

			int L=0,R=0;
			vector<int> vl,vr;

			int Q[600],head=0,tail=0;
			Q[tail++]=2*u;
			while(head<tail){
				int v=Q[head]/2,parity=Q[head]%2; head++;

				if(parity==0) L+=sz[v], vl.push_back(v);
				else          R+=sz[v], vr.push_back(v);

				rep(i,G[v].size()){
					int w=G[v][i];
					if(!vis[w]){
						vis[w]=true;
						Q[tail++]=2*w+(1-parity);
					}
				}
			}

			num.push_back(make_pair(L,R));
			vs.push_back(make_pair(vl,vr));
		}

		// 左, 右の割り当てが唯一存在するか
		// dp[i+1][j] := ( num[i] まで見たとき, 左に j 個割り当てる方法が何通りあるか )
		static int dp[601][301],pre[601][301];
		memset(dp,0,sizeof dp);
		dp[0][0]=1;
		rep(i,num.size()){
			int L=num[i].first,R=num[i].second;
			rep(j,n1-L+1){ dp[i+1][j+L]=min(dp[i+1][j+L]+dp[i][j],2); if(dp[i][j]>0) pre[i+1][j+L]=i*1000000+j*1000+0; }
			rep(j,n1-R+1){ dp[i+1][j+R]=min(dp[i+1][j+R]+dp[i][j],2); if(dp[i][j]>0) pre[i+1][j+R]=i*1000000+j*1000+1; }
		}

		if(dp[num.size()][n1]!=1){
			puts("no");
			continue;
		}

		// 割り当てを復元
		vector<int> ans;
		{
			int i=num.size(),j=n1;
			while(i>0){
				int ii=pre[i][j]/1000000;
				int jj=pre[i][j]/1000%1000;
				int parity=pre[i][j]%2;

				if(parity==0){
					rep(k,vs[i-1].first.size()){
						rep(u,n) if(id[U.find(u)]==vs[i-1].first[k]) ans.push_back(u);
					}
				}
				else{
					rep(k,vs[i-1].second.size()){
						rep(u,n) if(id[U.find(u)]==vs[i-1].second[k]) ans.push_back(u);
					}
				}

				i=ii;
				j=jj;
			}
		}

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

		rep(i,ans.size()) printf("%d\n",ans[i]+1);
		puts("end");
	}

	return 0;
}