constint N = 200010, M = N << 1; constint INF = 0x3f3f3f3f;
int n, m; char str[N], ch[10]; int rh[N], h[N], e[M], ne[M], idx; int que[M], hh = 0, tt = -1; int ans[N], cnt; // 记录答案 int indeg[N]; // 入度(冲突值) bool mark[N], tag[N];
inlinevoidadd(int *h, int a, int b){ e[++ idx] = b, ne[idx] = h[a], h[a] = idx; } // 这里使用邻接表的方式分别记录 第i个卡片可以去更新的点 第i个位置被覆盖后可以删去冲突的卡片
signedmain() { memset(h, -1, sizeof h), memset(rh, -1, sizeof rh); scanf("%d%d%s", &n, &m, str + 1); for (int i = 1, k, pos; i <= n; i ++) { scanf("%d", &k); while (k --) { scanf("%d%s", &pos, ch); if (ch[0] == str[pos]) add(h, i, pos + n); else { add(rh, pos + n, i); indeg[i] ++; // 第i张卡片的冲突增加 } tag[pos] = true; } } for (int ver = 1; ver <= m; ver ++) // 特判,否则会WA几个点 if (!tag[ver]) return !puts("-1"); for (int ver = 1; ver <= n; ver ++) if (!indeg[ver]) que[++ tt] = ver; while (hh <= tt) { int ver = que[hh ++]; ans[++ cnt] = ver; // 表示选择了当前卡片 for (int i = h[ver]; ~i; i = ne[i]) // 更新可以更新的点 { int pos = e[i]; if (mark[pos]) continue; mark[pos] = true; for (int j = rh[pos]; ~j; j = ne[j]) // 说明这些点已经被覆盖,让有冲突的卡片减少1 if (!-- indeg[e[j]]) que[++ tt] = e[j]; // 同拓扑排序 } } if (cnt == n) for (int i = 1; i <= cnt; i ++) printf("%d%c", ans[i], " \n"[i == cnt]); elseputs("-1"); return0; }