Submission #704964

#TimeUsernameProblemLanguageResultExecution timeMemory
704964CyanmondCrossing (JOI21_crossing)C++17
100 / 100
1276 ms115980 KiB
#include <bits/stdc++.h>

using i64 = long long;
constexpr i64 mod1 = 1000000007;
constexpr i64 mod2 = 998244353;

using T = std::pair<i64, i64>;
T addm1(T a, T b) {
    return {(a.first + b.first) % mod1, (a.second + b.second) % mod1};
}
T em() {
    return {0, 0};
}
T mapm1(i64 a, T b) {
    if (a == -1) return b;
    b.first = a * b.second;
    b.first %= mod1;
    return b;
}
i64 compm1(i64 a, i64 b) {
    if (a == -1) return b;
    return a;
}
i64 id() {
    return -1;
}

struct LazySegTreem1 {
    int n, size, logn;
    std::vector<T> node;
    std::vector<i64> lazy;

    void update(int i) {
        node[i] = addm1(node[2 * i], node[2 * i + 1]);
    }

    void ang(int i, i64 f) {
        node[i] = mapm1(f, node[i]);
        if (i < size) {
            lazy[i] = compm1(f, lazy[i]);
        }
    }

    void push(int i) {
        ang(2 * i, lazy[i]);
        ang(2 * i + 1, lazy[i]);
        lazy[i] = id();
    }

    LazySegTreem1() {}

    LazySegTreem1(const std::vector<T> &vec) {
        n = (int)vec.size();
        logn = 0;
        while ((1 << logn) < n) ++logn;
        size = 1 << logn;
        node.assign(2 * size, em());
        lazy.assign(size, id());
        std::copy(vec.begin(), vec.end(), node.begin() + size);
        for (int i = size - 1; i >= 1; --i) {
            update(i);
        }
    }

    void apply(int l, int r, i64 f) {
        l += size, r += size;
        for (int d = logn; d >= 1; --d) {
            if (((l >> d) << d) != l) push(l >> d);
            if (((r >> d) << d) != r) push((r - 1) >> d);
        }
        int l2 = l, r2 = r;
        while (l < r) {
            if (l & 1) ang(l++, f);
            if (r & 1) ang(--r, f);
            l /= 2, r /= 2;
        }
        l = l2, r = r2;
        for (int d = 1; d <= logn; ++d) {
            if (((l >> d) << d) != l) update(l >> d);
            if (((r >> d) << d) != r) update((r - 1) >> d);
        }
    }

    T fold(int l, int r) {
        l += size, r += size;
        for (int d = logn; d >= 1; --d) {
            if (((l >> d) << d) != l) push(l >> d);
            if (((r >> d) << d) != r) push((r - 1) >> d);
        }
        T pL = em(), pR = em();
        while (l < r) {
            if (l & 1) pL = addm1(pL, node[l++]);
            if (r & 1) pR = addm1(node[--r], pR);
            l /= 2;
            r /= 2;
        }
        return addm1(pL, pR);
    }
};

std::string cross(const std::string &a, const std::string &b) {
    std::string c;
    c.reserve(a.size());
    for (int i = 0; i < (int)a.size(); ++i) {
        if (a[i] == b[i]) {
            c.push_back(a[i]);
        } else {
            char x = 'J' xor 'O' xor 'I';
            x ^= a[i];
            x ^= b[i];
            c.push_back(x);
        }
    }
    return c;
}

constexpr i64 iHs = 7;
std::uniform_int_distribution<int> dist(0, 1000000000);
std::mt19937 mt(100);
std::array<i64, 3> h4 = {{999996919, 999976379, 999939407}}; 

int main() {
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);
    int N;
    std::cin >> N;
    std::vector<i64> powsm1(N);
    powsm1[0] = 1;
    for (int i = 1; i < N; ++i) {
        powsm1[i] = (powsm1[i - 1] * iHs) % mod1;
    }

    std::string S1, S2, S3;
    std::cin >> S1 >> S2 >> S3;
    int Q;
    std::cin >> Q;
    std::string T0;
    std::cin >> T0;
    std::vector<int> L(Q), R(Q);
    std::vector<char> C(Q);
    for (int i = 0; i < Q; ++i) {
        std::cin >> L[i] >> R[i] >> C[i];
        --L[i];
    }

    std::set<std::string> flowers;
    std::queue<std::string> ns;
    ns.push(S1);
    ns.push(S2);
    ns.push(S3);
    flowers.insert(S1);
    flowers.insert(S2);
    flowers.insert(S3);
    while (not ns.empty()) {
        const auto t = ns.front();
        ns.pop();
        auto nflowers = flowers;
        for (const auto &q : flowers) {
            const auto r = cross(t, q);
            if (nflowers.find(r) == nflowers.end()) {
                nflowers.insert(r);
                ns.push(r);
            }
        }
        flowers = nflowers;
    }

    const int M = (int)flowers.size();
    assert(M <= 20);
    std::vector<std::string> fs;
    for (const auto &e : flowers) {
        fs.push_back(e);
    }
    std::vector<LazySegTreem1> segm1s(M);
    for (int x = 0; x < M; ++x) {
        std::vector<T> initVecm1(N);
        for (int i = 0; i < N; ++i) {
            const auto v = (fs[x][i] == 'J' ? h4[0] : (fs[x][i] == 'O' ? h4[1] : h4[2]));
            initVecm1[i] = {(v * powsm1[i]) % mod1, powsm1[i]};
        }
        segm1s[x] = LazySegTreem1(initVecm1);
    }
    std::vector<T> initVecm1(N);
    for (int i = 0; i < N; ++i) {
        const auto v = (T0[i] == 'J' ? h4[0] : (T0[i] == 'O' ? h4[1] : h4[2]));
        initVecm1[i] = {(v * powsm1[i]) % mod1, powsm1[i]};
    }
    LazySegTreem1 iUsegm1(initVecm1);

    std::cout << (flowers.find(T0) != flowers.end() ? "Yes" : "No") << std::endl;
    for (int x = 0; x < Q; ++x) {
        iUsegm1.apply(L[x], R[x], (C[x] == 'J' ? h4[0] : (C[x] == 'O' ? h4[1] : h4[2])));
        bool answer = false;
        for (int i = 0; i < M; ++i) {
            bool b = iUsegm1.fold(0, N).first == segm1s[i].fold(0, N).first;
            if (b) answer = true;
        }
        std::cout << (answer ? "Yes" : "No") << std::endl;
    }
    /*
    std::vector<int> sameLimitL(M, N), sameLimitR(M, 0);
    std::vector<std::vector<std::pair<int, int>>> pressInfo(M);
    for (int x = 0; x < M; ++x) {
        const auto &f = fs[x];
        for (int i = 0; i < N; ++i) {
            if (f[i] != T0[i]) {
                sameLimitL[x] = i;
                break;
            }
        }
        for (int i = N - 1; i >= 0; --i) {
            if (f[i] != T0[i]) {
                sameLimitR[i] = i + 1;
                break;
            }
        }

        int lastI = 0;
        for (int i = 1; i < N; ++i) {
            if (fs[lastI] != fs[i]) {
                pressInfo[x].push_back({lastI, i - lastI});
                lastI = i;
            }
        }
        pressInfo[x].push_back({lastI, N - lastI});
    }

    std::cout << (flowers.find(T0) != flowers.end() ? "Yes" : "No") << std::endl;
    for (int i = 0; i < Q; ++i) {
        bool answer = false;
        for (int x = 0; x < M; ++x) {
            // judge
            if (sameLimitL[x] < L[i]) {
                continue;
            }
            if (sameLimitR[x] > R[i]) {
                continue;
            }
            auto itr = std::lower_bound(pressInfo[x].begin(), pressInfo[x].end(), std::make_pair(L[i], N + 1));
            --itr;
            if (itr->first + itr->second < R[i]) {
                continue;
            }
            if (fs[x][L[i]] != C[i]) {
                continue;
            }
            answer = true;
            break;
        }
        std::cout << (answer ? "Yes" : "No") << std::endl;
    }
    */
}
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...