제출 #1150314

#제출 시각아이디문제언어결과실행 시간메모리
1150314Perl32Crossing (JOI21_crossing)C++20
100 / 100
370 ms29712 KiB
//I wrote this code 4 u <3
#include <bits/stdc++.h>

using namespace std;
using ll = long long;

#ifdef LOCAL
#include "algo/debug.h"
#else
#define debug(...) 42
#endif

template <typename T>
T inverse(T a, T m) {
   T u = 0, v = 1;
   while (a != 0) {
      T t = m / a;
      m -= t * a; swap(a, m);
      u -= t * v; swap(u, v);
   }
   assert(m == 1);
   return u;
}

template <typename T>
class Modular {
 public:
   using Type = typename decay<decltype(T::value)>::type;

   constexpr Modular() : value() {}
   template <typename U>
   Modular(const U& x) {
      value = normalize(x);
   }

   template <typename U>
   static Type normalize(const U& x) {
      Type v;
      if (-mod() <= x && x < mod()) v = static_cast<Type>(x);
      else v = static_cast<Type>(x % mod());
      if (v < 0) v += mod();
      return v;
   }

   const Type& operator()() const { return value; }
   template <typename U>
   explicit operator U() const { return static_cast<U>(value); }
   constexpr static Type mod() { return T::value; }

   Modular& operator+=(const Modular& other) { if ((value += other.value) >= mod()) value -= mod(); return *this; }
   Modular& operator-=(const Modular& other) { if ((value -= other.value) < 0) value += mod(); return *this; }
   template <typename U> Modular& operator+=(const U& other) { return *this += Modular(other); }
   template <typename U> Modular& operator-=(const U& other) { return *this -= Modular(other); }
   Modular& operator++() { return *this += 1; }
   Modular& operator--() { return *this -= 1; }
   Modular operator++(int) { Modular result(*this); *this += 1; return result; }
   Modular operator--(int) { Modular result(*this); *this -= 1; return result; }
   Modular operator-() const { return Modular(-value); }

   template <typename U = T>
   typename enable_if<is_same<typename Modular<U>::Type, int>::value, Modular>::type& operator*=(const Modular& rhs) {
      value = normalize(static_cast<int64_t>(value) * static_cast<int64_t>(rhs.value));
      return *this;
   }
   template <typename U = T>
   typename enable_if<is_same<typename Modular<U>::Type, long long>::value, Modular>::type& operator*=(const Modular& rhs) {
      long long q = static_cast<long long>(static_cast<long double>(value) * rhs.value / mod());
      value = normalize(value * rhs.value - q * mod());
      return *this;
   }
   template <typename U = T>
   typename enable_if<!is_integral<typename Modular<U>::Type>::value, Modular>::type& operator*=(const Modular& rhs) {
      value = normalize(value * rhs.value);
      return *this;
   }

   Modular& operator/=(const Modular& other) { return *this *= Modular(inverse(other.value, mod())); }

   friend const Type& abs(const Modular& x) { return x.value; }

   template <typename U>
   friend bool operator==(const Modular<U>& lhs, const Modular<U>& rhs);

   template <typename U>
   friend bool operator<(const Modular<U>& lhs, const Modular<U>& rhs);

   template <typename V, typename U>
   friend V& operator>>(V& stream, Modular<U>& number);

private:
   Type value;
};

template <typename T> bool operator==(const Modular<T>& lhs, const Modular<T>& rhs) { return lhs.value == rhs.value; }
template <typename T, typename U> bool operator==(const Modular<T>& lhs, U rhs) { return lhs == Modular<T>(rhs); }
template <typename T, typename U> bool operator==(U lhs, const Modular<T>& rhs) { return Modular<T>(lhs) == rhs; }

template <typename T> bool operator!=(const Modular<T>& lhs, const Modular<T>& rhs) { return !(lhs == rhs); }
template <typename T, typename U> bool operator!=(const Modular<T>& lhs, U rhs) { return !(lhs == rhs); }
template <typename T, typename U> bool operator!=(U lhs, const Modular<T>& rhs) { return !(lhs == rhs); }

template <typename T> bool operator<(const Modular<T>& lhs, const Modular<T>& rhs) { return lhs.value < rhs.value; }

template <typename T> Modular<T> operator+(const Modular<T>& lhs, const Modular<T>& rhs) { return Modular<T>(lhs) += rhs; }
template <typename T, typename U> Modular<T> operator+(const Modular<T>& lhs, U rhs) { return Modular<T>(lhs) += rhs; }
template <typename T, typename U> Modular<T> operator+(U lhs, const Modular<T>& rhs) { return Modular<T>(lhs) += rhs; }

template <typename T> Modular<T> operator-(const Modular<T>& lhs, const Modular<T>& rhs) { return Modular<T>(lhs) -= rhs; }
template <typename T, typename U> Modular<T> operator-(const Modular<T>& lhs, U rhs) { return Modular<T>(lhs) -= rhs; }
template <typename T, typename U> Modular<T> operator-(U lhs, const Modular<T>& rhs) { return Modular<T>(lhs) -= rhs; }

template <typename T> Modular<T> operator*(const Modular<T>& lhs, const Modular<T>& rhs) { return Modular<T>(lhs) *= rhs; }
template <typename T, typename U> Modular<T> operator*(const Modular<T>& lhs, U rhs) { return Modular<T>(lhs) *= rhs; }
template <typename T, typename U> Modular<T> operator*(U lhs, const Modular<T>& rhs) { return Modular<T>(lhs) *= rhs; }

template <typename T> Modular<T> operator/(const Modular<T>& lhs, const Modular<T>& rhs) { return Modular<T>(lhs) /= rhs; }
template <typename T, typename U> Modular<T> operator/(const Modular<T>& lhs, U rhs) { return Modular<T>(lhs) /= rhs; }
template <typename T, typename U> Modular<T> operator/(U lhs, const Modular<T>& rhs) { return Modular<T>(lhs) /= rhs; }

template<typename T, typename U>
Modular<T> power(const Modular<T>& a, const U& b) {
   Modular<T> x = a, res = 1;
   U p = b;
   while (p > 0) {
      if (p & 1) res *= x;
      x *= x;
      p >>= 1;
   }
   return res;
}

template <typename T>
bool IsZero(const Modular<T>& number) {
   return number() == 0;
}

template <typename T>
string to_string(const Modular<T>& number) {
   return to_string(number());
}

template <typename U, typename T>
U& operator<<(U& stream, const Modular<T>& number) {
   return stream << number();
}

template <typename U, typename T>
U& operator>>(U& stream, Modular<T>& number) {
   typename common_type<typename Modular<T>::Type, long long>::type x;
   stream >> x;
   number.value = Modular<T>::normalize(x);
   return stream;
}

constexpr int mod = 1e9 + 7;
using mint = Modular<std::integral_constant<decay<decltype(mod)>::type, mod>>;

template<>
struct std::hash<mint> {
    ll operator()(const mint& a) const {
        return (ll) a;
    }
};

const int maxN = 2e5 + 2e3;

const int R = 5;
mint pw[maxN];
mint spw[maxN];

void precalc() {
    pw[0] = 1;
    spw[0] = 1;
    for (int i = 1; i < maxN; ++i) {
        pw[i] = pw[i - 1] * R;
        spw[i] = spw[i - 1] + pw[i];
    }
}

int conv(char c) {
    if (c == 'J') {
        return 1;
    } else if (c == 'O') {
        return 2;
    }
    return 3;
}

struct Info {
   mint hsh = 0;
   int sz = 0;
   Info() = default;
   Info(int v) : hsh(v), sz(1) {}
};

Info operator+(const Info &a, const Info &b) {
   Info ret;
   ret.hsh = a.hsh * pw[b.sz] + b.hsh;
   ret.sz = a.sz + b.sz;
   return ret;
}

struct Tag {
   bool st = 0;
   int v = 0;

   Tag() = default;
   explicit Tag(int _v) {
      st = 1;
      v = _v;
   }
};

void apply(Info &a, Tag b) {
   if (b.st) {
       if (a.sz) {
           a.hsh = b.v * spw[a.sz - 1];
       }
   }
}

void apply(Tag &a, Tag b) {
   if (b.st) {
       a = b;
   }
}

template<class Info, class Tag, class Merge = plus<Info>>
class LazySegTree {
public:
   int sz;
   const Merge merge;
   vector<Info> t;
   vector<Tag> tag;

   LazySegTree() = default;

   LazySegTree(int n, const Info &v = Info()) : merge(Merge()) {
      sz = 1;
      while (sz < n) sz <<= 1;
      t.assign(sz << 1, Info());
      tag.assign(sz << 1, {});
      for (int i = 0; i < n; ++i) {
         t[i + sz] = v;
      }
      for (int i = sz - 1; i > 0; --i) {
         pull(i);
      }
   }

   LazySegTree(const vector<Info> &a) : merge(Merge()) {
      sz = 1;
      while (sz < (int) a.size()) sz <<= 1;
      t.resize(sz << 1), tag.assign(sz << 1, {});
      for (int i = 0; i < int(a.size()); ++i) {
         t[i + sz] = a[i];
      }
      for (int i = sz - 1; i > 0; --i) {
         pull(i);
      }
   }

   void pull(int x) {
      t[x] = merge(t[x << 1], t[x << 1 | 1]);
   }

   void apply(int p, const Tag &v) {
      ::apply(t[p], v);
      ::apply(tag[p], v);
   }

   void push(int x) {
      apply(x << 1, tag[x]);
      apply(x << 1 | 1, tag[x]);
      tag[x] = Tag();
   }

   Info get(int l, int r, int x, int lx, int rx) {
      if (l >= rx || lx >= r) {
         return Info();
      }
      if (l <= lx && rx <= r) {
         return t[x];
      }
      int m = (lx + rx) >> 1;
      push(x);
      return merge(get(l, r, x << 1, lx, m), get(l, r, x << 1 | 1, m, rx));
   }

   Info get(int l, int r) {
      return get(l, r, 1, 0, sz);
   }

   Info get(int i, int x, int lx, int rx) {
      if (lx + 1 == rx) {
         return t[x];
      }
      int m = (lx + rx) >> 1;
      push(x);
      if (i < m) return get(i, x << 1, lx, m);
      else return get(i, x << 1 | 1, m, rx);
   }

   Info get(int i) {
      return get(i, 1, 0, sz);
   }

   void upd(int l, int r, const Tag v, int x, int lx, int rx) {
      if (l >= rx || lx >= r) {
         return;
      }
      if (l <= lx && rx <= r) {
         apply(x, v);
         return;
      }
      int m = (lx + rx) >> 1;
      push(x);
      upd(l, r, v, x << 1, lx, m);
      upd(l, r, v, x << 1 | 1, m, rx);
      pull(x);
   }

   void upd(int l, int r, Tag v) {
      upd(l, r, v, 1, 0, sz);
   }

   void upd(int i, Info v, int x, int lx, int rx) {
      if (lx + 1 == rx) {
         t[x] = v;
         return;
      }
      int m = (lx + rx) >> 1;
      push(x);
      if (i < m) upd(i, v, x << 1, lx, m);
      else upd(i, v, x << 1 | 1, m, rx);
      pull(x);
   }

   void upd(int i, Info v) {
      upd(i, v, 1, 0, sz);
   }

   Info prod() { return t[1]; }
};

signed main(int32_t argc, char *argv[]) {
    ios_base::sync_with_stdio(false);
    cin.tie(nullptr);

    precalc();
    int n;
    cin >> n;
    vector<vector<int>> a(3, vector<int>(n));
    for (auto& x : a) {
        for (auto& y : x) {
            char c;
            cin >> c;
            y = conv(c);
        }
    }
    auto prod = [&](int x, int y) {
        if (x == y) return x;
        return 6 - (x + y);
    };
    queue<vector<int>> que;
    unordered_map<mint, bool> have;
    for (int i = 0; i < 3; ++i) {
        que.push(a[i]);
        mint cur = 0;
        for (auto x : a[i]) {
            cur = cur * R + x;
        }
        have[cur] = 1;
    }
    vector<int> nw(n);
    while (!que.empty()) {
        auto s = que.front(); que.pop();
        vector<vector<int>> ex;
        for (auto& t : a) {
            mint cur = 0;
            for (int j = 0; j < n; ++j) {
                nw[j] = prod(s[j], t[j]);
                cur = cur * R + nw[j];
            }
            if (have.find(cur) == have.end()) {
                have[cur] = 1;
                ex.push_back(nw);
                que.push(nw);
            }
        }
        for (auto& x : ex) a.push_back(x);
    }
    int q;
    cin >> q;
    vector<Info> t(n);
    for (auto& x : t) {
        char c;
        cin >> c;
        if (c == 'J') {
            x = Info(1);
        } else if (c == 'O') {
            x = Info(2);
        } else {
            x = Info(3);
        }
    }
    LazySegTree<Info, Tag> tt(t);
    cout << (have[tt.prod().hsh] ? "Yes" : "No") << '\n';
    while (q--) {
        int l, r;
        char c;
        cin >> l >> r >> c;
        --l;
        tt.upd(l, r, Tag(conv(c)));
        cout << (have[tt.prod().hsh] ? "Yes" : "No") << '\n';
    }
}

/*

 */
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...