「Ynoi Easy Round 2016」谁的梦

思路简单,代码不难。

首先考虑不带修改怎么做,经典正难反易,先转化为对每个颜色求有多少种选法使得存在该颜色 \(c\),然后用整体减去不包含颜色 \(c\) 的方案数得到不存在颜色 \(c\) 的方案数 \(f(c)\),设所有出现过的颜色数为 \(t\),将颜色离散化,那答案就等于 \(t \sum_{i = 1}^n \frac{len_i (len_i + 1)}{2} - \sum_{c = 1}^t f(c)\)

设颜色 \(c\) 在第 \(i\) 个序列中出现了 \(k\) 次,出现位置集合为 \(p_{c, i} (p_{c, i, 0} = 0, p_{c, i, k + 1} = len_i + 1)\),则 \(f(c) = \sum_{i = 1}^n \sum_{j = 1}^{k + 1} \frac{(p_j - p_{j - 1})(p_j - p_{j - 1} - 1)}{2}\)。观察可得当我们修改一个位置元素时等价与删除原本那个元素后再插入一个新元素,对于每个元素在每个它出现的序列维护一个 set 来维护插入删除,进一步发现影响答案的只有插入或删除元素相邻两个元素构成的区间的合并与分裂、在插入删除时更新一下即可。

然后记得记录一下 \(\times 0\) 的个数,因为 \(0\) 没有逆元,不能直接用逆元乘。

时间复杂度 \(O(N \log N)\),空间复杂度 \(O(N)\)

/*
address:https://www.luogu.com.cn/problem/P4692
AC 2026/8/8 11:06
*/
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int mod = 19260817;
const int N = 1e5 + 5;
int n, q;
int len[N];
vector<int>a[N];
LL mul[N << 1], all, ans;
int cnt[N << 1], cnt0[N << 1];
LL val[N];
int disc[N << 1], t;
int X[N], Y[N], Z[N];
map<int, set<int>>s[N];
map<int, LL>sum[N];
inline LL power(LL a, LL k) {
    a %= mod;
    LL ret = 1;
    while (k > 0) {
        if (k & 1) ret = ret * a % mod;
        a = a * a % mod;
        k >>= 1;
    }
    return ret;
}
inline void trans(LL& x, LL y) { x = (x + y) % mod; }
inline void insert(int x, int y, int z) {
    if (!s[x].count(z)) s[x][z].insert(0), s[x][z].insert(len[x] + 1), sum[x][z] = 1ll * len[x] * (len[x] + 1) >> 1;
    auto p = s[x][z].upper_bound(y);
    auto q = p;--q;
    const int l = *q, r = *p;
    trans(ans, cnt0[z] ? 0 : -mul[z]);
    mul[z] = mul[z] * power(sum[x][z], mod - 2) % mod;
    sum[x][z] -= val[r - l - 1];
    sum[x][z] += val[y - l - 1] + val[r - y - 1];
    if (sum[x][z]) mul[z] = mul[z] * sum[x][z] % mod;
    else ++cnt0[z];
    trans(ans, cnt0[z] ? 0 : mul[z]);
    s[x][z].insert(y);
}
inline void erase(int x, int y, int z) {
    auto p = s[x][z].lower_bound(y);
    auto l = p, r = p;
    --l, ++r;
    trans(ans, cnt0[z] ? 0 : -mul[z]);
    if (sum[x][z]) mul[z] = mul[z] * power(sum[x][z], mod - 2) % mod;
    else --cnt0[z];
    sum[x][z] -= val[y - *l - 1] + val[*r - y - 1];
    sum[x][z] += val[*r - *l - 1];
    mul[z] = mul[z] * sum[x][z] % mod;
    trans(ans, cnt0[z] ? 0 : mul[z]);
    s[x][z].erase(y);
}
inline void init() {
    int mxlen = 0;
    for (int i = 1;i <= n;++i) mxlen = max(mxlen, int(a[i].size()));
    for (int i = 1;i <= mxlen;++i) val[i] = (1ll * i * (i + 1) >> 1);
    mul[0] = 1;
    for (int i = 1;i <= n;++i) mul[0] = mul[0] * (1ll * (len[i] + 1) * len[i] >> 1) % mod;
    for (int i = 1;i <= t;++i) mul[i] = mul[0], trans(ans, mul[i]);
    all = ans;
    for (int i = 1;i <= n;++i)
        for (int j = 1;j <= len[i];++j) insert(i, j, a[i][j]);
}
int main() {
    scanf("%d%d", &n, &q);
    for (int i = 1;i <= n;++i) scanf("%d", &len[i]), a[i].resize(len[i] + 2);
    for (int i = 1;i <= n;++i)
        for (int j = 1;j <= len[i];++j) scanf("%d", &a[i][j]), disc[++t] = a[i][j];
    for (int i = 1;i <= q;++i) scanf("%d%d%d", &X[i], &Y[i], &Z[i]), disc[++t] = Z[i];
    sort(disc + 1, disc + t + 1);
    t = unique(disc + 1, disc + t + 1) - disc - 1;
    for (int i = 1;i <= n;++i)
        for (int j = 1;j <= len[i];++j) a[i][j] = lower_bound(disc + 1, disc + t + 1, a[i][j]) - disc;
    init();
    printf("%lld\n", (all - ans + mod) % mod);
    for (int i = 1;i <= q;++i) {
        int x = X[i], y = Y[i], z = lower_bound(disc + 1, disc + t + 1, Z[i]) - disc;
        erase(x, y, a[x][y]);
        insert(x, y, z);
        a[x][y] = z;
        printf("%lld\n", (all - ans + mod) % mod);
    }
    return 0;
}
posted @ 2026-08-08 11:40  keysky  阅读(3)  评论(0)    收藏  举报