#include<bits/stdc++.h>
using namespace std;
const int MAXN = 1e6 + 5;
int pos, len, lastVal;
string str;
int tot = 0, ty[MAXN], ch[MAXN][2];
int buildThis(vector<int> &tt, vector<int> &op, int l, int r) {
for (int i = l; i <= r; i++) {
if (op[i] == )
}
}
int buildExpress() {
vector<int> tt, op;
while (pos < len) {
if (str[pos] == '(') {
pos++;
tt.push_back(buildExpress());
} else if (str[pos] == '!') {
pos++;
int g = ++tot;
ty[g] = -1, ch[g][0] = buildExpress();
tt.push_back(g);
} else if (str[pos] == 'x') {
ty[++tot] = 2, tt.push_back(tot), pos++;
} else if (str[pos] == 'y') {
ty[++tot] = 3, tt.push_back(tot), pos++;
} else if (str[pos] == '0') {
ty[++tot] = 0, tt.push_back(tot), pos++;
} else if (str[pos] == '1') {
ty[++tot] = 1, tt.push_back(tot), pos++;
} else if (str[pos] == '&') {
op.push_back(-2), pos++;
} else if (str[pos] == '|') {
op.push_back(-3), pos++;
} else if (str[pos] == '^') {
op.push_back(-4), pos++;
} else if (str[pos] == '=') {
op.push_back(-5), pos++;
} else if(str[pos] == ')') {
pos++;
break;
}
}
return buildThis(&tt, &op, 0, op.size());
}
int dfs(int x, int val_x, int val_y) {
if (ty[x] == 2) return val_x;
if (ty[x] == 3) return val_y;
if (ty[x] >= 0) return ty[x];
if (ty[x] == -1) return !dfs(ch[x][0], val_x, val_y);
if (ty[x] == -2) {
return dfs(ch[x][0], val_x, val_y) & dfs(ch[x][1], val_x, val_y);
}
if (ty[x] == -3) {
return dfs(ch[x][0], val_x, val_y) | dfs(ch[x][1], val_x, val_y);
}
if (ty[x] == -4) {
return dfs(ch[x][0], val_x, val_y) ^ dfs(ch[x][1], val_x, val_y);
}
if (ty[x] == -5) {
return dfs(ch[x][0], val_x, val_y) == dfs(ch[x][1], val_x, val_y);
}
}
int calc(string s) {
pos = 0, str = s, len = str.size();
tot = 0;
int rt = buildExpress(), sta = 0;
for (int x = 0; x <= 1; x++) {
for (int y = 0; y <= 1; y++) {
if (dfs(rt, x, y)) sta |= 1 << (x << 1 | y);
}
}
return sta;
}
struct Node {
int a, b, sta, val;
};
vector<Node> f;
map<pair<pair<int, int>, int>, bool> tt;
bitset<1024> S[10][4], full;
bitset<1024> getLimit(int A) {
bitset<1024> now = full, lim = 0;
for (auto node : f) {
int a = node.a, b = node.b, sta = node.sta, val = node.val;
int x = A >> a & 1, pp = 0;
for (int y = 0; y <= 1; y++) {
if (sta >> (x << 1 | y) & 1) {
pp |= 1 << y;
}
}
if (val == 1) {
lim |= now & S[b][pp];
}
now &= S[b][pp ^ 3];
}
if (lastVal) {
lim |= now;
}
return lim;
}
bitset<1024> outEdge[1024];
void solve() {
int n, k;
cin >> n >> k;
for (int i = 1; i <= n; i++) {
int a, b, val;
string s;
cin >> a >> b >> s >> val;
a--, b--;
int t = calc(s);
if (tt.find(make_pair(make_pair(a, b), t)) == tt.end()) {
tt[make_pair(make_pair(a, b), t)] = 1;
f.push_back((Node){a, b, t, val});
}
}
cin >> lastVal;
for (int x = 0; x < 1 << k; x++) full.set(x);
for (int b = 0; b < k; b++) {
S[b][0] = 0, S[b][3] = full;
for (int i = 0; i < 1 << k; i++) {
if (i >> b & 1) S[b][2].set(i);
else S[b][1].set(i);
}
}
for (int x = 0; x < 1 << k; x++) {
outEdge[x] = getLimit(x);
}
int ansA = 0, ansB = 0, ansC = 0;
for (int x = 0; x < (1 << k); x++) {
if (outEdge[x][x]) ansA++;
for (int y = 0; y < (1 << k); y++) if(outEdge[x][y]) {
if (outEdge[y][x]) ansB++;
ansC += (~outEdge[x] & outEdge[y]).count();
}
}
cout << ansA << ' ' << ansB << ' ' << ansC << '\n';
}
int main() {
solve();
return 0;
}