CF2064E Mycraft Sand Sort Solution

· · 题解

这说明你的实力不足以上 Master。

唐题,但是我没有场切。

我们有以下的观察:

然后其实就做完了。我们考虑维护相邻的极大同色块,这个可以并查集,从小到大枚举数,我们发现当前的数能换到的位置就是这个块的大小,所以答案累乘,然后因为这个数并不影响之后的数的放置,所以把这个数删去,如果这个数上下的数同色,那么合并,这个可以用链表维护,然后最后输出答案即可。

代码很好写。不知道为什么官解用了线段树,比较抽象。

#include <bits/stdc++.h>
#define LL long long
using namespace std;
const int N = 2e5 + 10;
const LL MOD = 998244353;
int n, A[N], C[N], nxt[N], pre[N]; pair<int, int> p[N];
int fa[N], sz[N]; 
int Find(int x) { return (fa[x] == x ? x : fa[x] = Find(fa[x])); };
void merge(int a, int b) {
    int x = Find(a), y = Find(b);
    if (x == y) return ;
    fa[x] = y; sz[y] += sz[x]; sz[x] = 0;
}
int main() {
    freopen(".in", "r", stdin); freopen(".out", "w", stdout);
    ios :: sync_with_stdio(0); cin.tie(0); cout.tie(0);
    int _; cin >> _;
    while (_ --) {
        cin >> n;
        for (int i = 1; i <= n; i ++) { cin >> A[i]; p[i] = {A[i], i}; }
        for (int i = 1; i <= n; i ++) cin >> C[i];
        for (int i = 1; i <= n; i ++) fa[i] = i, sz[i] = 1;
        sort(p + 1, p + 1 + n); LL Ans = 1; C[n + 1] = 114514191; nxt[0] = 1, pre[n + 1] = n;
        for (int i = 1; i <= n; i ++) nxt[i] = i + 1, pre[i] = i - 1;
        for (int i = 2; i <= n; i ++) if (C[i] == C[i - 1]) merge(i, i - 1);
        for (int i = 1; i <= n; i ++) {
            int u = p[i].second;
            Ans = Ans * sz[Find(u)] % MOD; sz[Find(u)] --;
            if (C[nxt[u]] == C[pre[u]]) merge(nxt[u], pre[u]);
            nxt[pre[u]] = nxt[u]; pre[nxt[u]] = pre[u];
        } cout << Ans << "\n";
    }
    return 0;
}