#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace std; #define PROFILE_START(i) clock_t start##i = clock() #define PROFILE_STOP(i) fprintf(stderr, "elapsed time (" #i ") = %f\n", double(clock() - start##i) / CLOCKS_PER_SEC) typedef long long ll; typedef unsigned long long ull; typedef vector vi; typedef pair pii; typedef pair pll; #define fi first #define se second #define pb push_back #define eb emplace_back #define em emplace #define mp make_pair #define mt make_tuple template > struct CompactSegmentTree { int N; // the size of array vector tree; // T defaultValue; BinOp mergeOp; CompactSegmentTree(int size, T dflt = T()) : N(size + (size & 1)), tree((size + (size & 1)) * 2, dflt), mergeOp(), defaultValue(dflt) { } CompactSegmentTree(int size, BinOp op, T dflt = T()) : N(size + (size & 1)), tree((size + (size & 1)) * 2, dflt), mergeOp(op), defaultValue(dflt) { } void init(T value, int size) { for (int i = 0; i < size; i++) tree[N + i] = value; for (int i = N - 1; i > 0; i--) tree[i] = mergeOp(tree[i << 1], tree[(i << 1) | 1]); } void build(const vector& v) { for (int i = 0; i < (int)v.size(); i++) tree[N + i] = v[i]; for (int i = N - 1; i > 0; i--) tree[i] = mergeOp(tree[i << 1], tree[(i << 1) | 1]); } void build(const T arr[], int size) { for (int i = 0; i < size; i++) tree[N + i] = arr[i]; for (int i = N - 1; i > 0; i--) tree[i] = mergeOp(tree[i << 1], tree[(i << 1) | 1]); } T query(int index) { T res = defaultValue; for (index += N; index > 0; index >>= 1) res = mergeOp(res, tree[index]); return res; } // inclusive T query(int left, int right) { T resL = defaultValue; T resR = defaultValue; for (int L = left + N, R = right + N + 1; L < R; L >>= 1, R >>= 1) { if (L & 1) resL = mergeOp(resL, tree[L++]); if (R & 1) resR = mergeOp(tree[--R], resR); } return mergeOp(resL, resR); } void update(int index, T newValue) { tree[index + N] = newValue; for (int i = (index + N) >> 1; i > 0; i >>= 1) tree[i] = mergeOp(tree[i << 1], tree[(i << 1) | 1]); } // inclusive void updateRange(int left, int right, T newValue) { for (int L = left + N, R = right + N + 1; L < R; L++) tree[L] = newValue; for (int L = (left + N) >> 1, R = (right + N) >> 1; L > 0; L >>= 1, R >>= 1) { for (int i = L; i <= R; i++) tree[i] = mergeOp(tree[i << 1], tree[(i << 1) | 1]); } } void add(int index, T value) { tree[index + N] += value; for (int i = (index + N) >> 1; i > 0; i >>= 1) tree[i] = mergeOp(tree[i << 1], tree[(i << 1) | 1]); } // inclusive void addRange(int left, int right, T value) { for (int L = left + N, R = right + N + 1; L < R; L++) tree[L] += value; for (int L = (left + N) >> 1, R = (right + N) >> 1; L > 0; L >>= 1, R >>= 1) { for (int i = L; i <= R; i++) tree[i] = mergeOp(tree[i << 1], tree[(i << 1) | 1]); } } }; template CompactSegmentTree makeCompactSegmentTree(int size, BinOp op, T dfltValue = T()) { return std::move(CompactSegmentTree(size, op, dfltValue)); } template CompactSegmentTree makeCompactSegmentTree(const vector& v, BinOp op, T dfltValue = T()) { auto segTree = CompactSegmentTree((int)v.size(), op, dfltValue); segTree.build(v); return std::move(segTree); } template CompactSegmentTree makeCompactSegmentTree(const T arr[], int size, BinOp op, T dfltValue = T()) { auto segTree = CompactSegmentTree(size, op, dfltValue); segTree.build(arr, size); return std::move(segTree); } template > struct CompactSegmentTreeLazyAdd { int N; // the size of array int H; // the height of the tree vector tree; // vector treeLazy; // 0 means "not lazy value" T defaultValue; BinOp mergeOp; CompactSegmentTreeLazyAdd(int size, T dflt = T()) : N(size + (size & 1)), tree(N * 2, dflt), treeLazy(N, dflt), mergeOp(), defaultValue(dflt) { H = 0; for (int i = N; i; i >>= 1) H++; } CompactSegmentTreeLazyAdd(int size, BinOp op, T dflt = T()) : N(size + (size & 1)), tree(N * 2, dflt), treeLazy(N, dflt), mergeOp(op), defaultValue(dflt) { H = 0; for (int i = N; i; i >>= 1) H++; } void init(T value, int size) { for (int i = 0; i < size; i++) tree[N + i] = value; for (int i = N - 1; i > 0; i--) tree[i] = mergeOp(tree[i << 1], tree[(i << 1) | 1]); } void build(const vector& v) { for (int i = 0; i < (int)v.size(); i++) tree[N + i] = v[i]; for (int i = N - 1; i > 0; i--) tree[i] = mergeOp(tree[i << 1], tree[(i << 1) | 1]); } void build(const T arr[], int size) { for (int i = 0; i < size; i++) tree[N + i] = arr[i]; for (int i = N - 1; i > 0; i--) tree[i] = mergeOp(tree[i << 1], tree[(i << 1) | 1]); } T query(int index) { return query(index, index); } // inclusive T query(int left, int right) { pushDown(left + N); if (left != right) pushDown(right + N); T resL = defaultValue; T resR = defaultValue; for (int L = left + N, R = right + N + 1; L < R; L >>= 1, R >>= 1) { if (L & 1) resL = mergeOp(resL, tree[L++]); if (R & 1) resR = mergeOp(tree[--R], resR); } return mergeOp(resL, resR); } void add(int index, T value) { addRange(index, index, value); } // inclusive void addRange(int left, int right, T value) { for (int L = left + N, R = right + N + 1; L < R; L >>= 1, R >>= 1) { if (L & 1) apply(L++, value); if (R & 1) apply(--R, value); } pushUp(left + N); if (left != right) pushUp(right + N); } private: void apply(int index, T value) { tree[index] += value; if (index < N) treeLazy[index] += value; } void pushUp(int index) { while (index > 1) { index >>= 1; tree[index] = mergeOp(tree[index << 1], tree[(index << 1) | 1]) + treeLazy[index]; } } void pushDown(int index) { for (int shift = H; shift > 0; --shift) { int i = index >> shift; if (treeLazy[i]) { apply((i << 1), treeLazy[i]); apply((i << 1) | 1, treeLazy[i]); treeLazy[i] = 0; } } } }; template CompactSegmentTreeLazyAdd makeCompactSegmentTreeLazyAdd(int size, BinOp op, T dfltValue = T()) { return std::move(CompactSegmentTreeLazyAdd(size, op, dfltValue)); } template struct FenwickTree { vector tree; FenwickTree(int n) : tree(n + 1) { // no action } void clear() { fill(tree.begin(), tree.end(), 0); } void init(T arr[], int n) { for (int i = 0; i < n; i++) add(i, arr[i]); } void init(vector& v, int n) { for (int i = 0; i < n; i++) add(i, v[i]); } // sum from 0 to pos T sum(int pos) { pos++; T res = 0; while (pos > 0) { res += tree[pos]; pos &= pos - 1; // clear lowest bit } return res; } // inclusive T sumRange(int left, int right) { T res = sum(right); if (left > 0) res -= sum(left - 1); return res; } void add(int pos, T val) { pos++; while (pos < (int)tree.size()) { tree[pos] += val; pos += pos & -pos; // add lowest bit } } // inclusive void addRange(int left, int right, T val) { add(left, val); if (right + 1 < (int)tree.size() - 1) add(right + 1, -val); } }; #define MAXM 50000 #define MAXN 50000 enum { aE, aD, aC, aM }; bool gP[4][4] = { { true , false, true , false }, { false, true , false, true }, { true , false, true , false }, { false, true , false, true }, }; int gM, gN; #if 0 vector solve(vector& v, vector& s, vector& t) { vector> Q; for (int i = 0; i < gN; i++) { if (s[i] >= t[i]) continue; Q.emplace_back(s[i], true, v[i]); Q.emplace_back(t[i], false, v[i]); } sort(Q.begin(), Q.end()); auto trEC = makeCompactSegmentTree(gM + 1, [](int a, int b) { return max(a, b); }, 0); auto trDM = makeCompactSegmentTree(gM + 1, [](int a, int b) { return max(a, b); }, 0); int prevMax = 0; int deltaEC = 0, deltaDM = 0, currEC = 0, currDM = 0; for (int i = 0; i < (int)Q.size(); i++) { int x = get<0>(Q[i]); bool lt = get<1>(Q[i]); int t = get<2>(Q[i]); if (lt) { if (t == aE || t == aC) deltaEC++; else deltaDM++; } else { if (t == aE || t == aC) { trEC.update(x, prevMax + ++currEC); deltaEC--; } else { trDM.update(x, prevMax + ++currDM); deltaDM--; } if (deltaDM == 0 && deltaEC == 0) { //prevMax = max(trEC.query(0, x), trDM.query(0, x)); prevMax += max(currEC, currDM); currEC = 0; currDM = 0; } } } vector ans(gM + 1); for (int i = 1; i < gM; i++) { ans[i] = max(trEC.query(0, i), trDM.query(0, i)); } vector res(gN, -1); int d = 0; for (int i = 0; i < gM; i++) { while (d < ans[i] && d < gN) { res[d++] = i + 1; } } return move(res); } #else vector solve(vector& v, vector& s, vector& t) { vector>> Q(gM); for (int i = 0; i < gN; i++) { if (s[i] >= t[i]) continue; Q[t[i]].emplace_back(s[i], v[i]); } FenwickTree ftEC(gM + 1); FenwickTree ftDM(gM + 1); auto trEC = makeCompactSegmentTreeLazyAdd(gM + 1, [](int a, int b) { return max(a, b); }, 0); auto trDM = makeCompactSegmentTreeLazyAdd(gM + 1, [](int a, int b) { return max(a, b); }, 0); vector dpEC(gM); vector dpDM(gM); vector ans(gM); unordered_map cntEC; unordered_map cntDM; for (int i = 1; i < gM; i++) { dpEC[i] = dpEC[i - 1]; dpDM[i] = dpDM[i - 1]; if (!Q[i].empty()) { sort(Q[i].begin(), Q[i].end()); for (int j = 0; j < (int)Q[i].size(); j++) { int L = get<0>(Q[i][j]); int R = i; int T = get<1>(Q[i][j]); if (T == aE || T == aC) { //ftEC.add(L, 1); trEC.addRange(0, L, 1); } else { //ftDM.add(L, 1); trDM.addRange(0, L, 1); } } /* for (int j = 0; j < i; j++) { int L = j; dpEC[i] = max(dpEC[i], ans[L] + ftEC.sumRange(L, i)); dpDM[i] = max(dpDM[i], ans[L] + ftDM.sumRange(L, i)); } */ dpEC[i] = trEC.query(0, i - 1); dpDM[i] = trDM.query(0, i - 1); } ans[i] = max(dpEC[i], dpDM[i]); trEC.add(i, ans[i]); trDM.add(i, ans[i]); } vector res(gN, -1); int d = 0; for (int i = 0; i < gM; i++) { while (d < ans[i] && d < gN) { res[d++] = i + 1; } } return move(res); } #endif int main(void) { ios_base::sync_with_stdio(false); cin.tie(nullptr); int T; cin >> T; while (T-- > 0) { cin >> gM >> gN; vector v(gN); for (int i = 0; i < gN; i++) { char t; cin >> t; switch (t) { case 'E': v[i] = aE; break; case 'D': v[i] = aD; break; case 'C': v[i] = aC; break; case 'M': v[i] = aM; break; } } vector s(gN); for (int i = 0; i < gN; i++) { cin >> s[i]; --s[i]; } vector t(gN); for (int i = 0; i < gN; i++) { cin >> t[i]; --t[i]; } auto ans = solve(v, s, t); cout << ans[0]; for (int i = 1; i < gN; i++) cout << " " << ans[i]; cout << endl; } return 0; }