Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #ifdef _DEBUG
- #define _CRT_SECURE_NO_WARNINGS
- #endif
- #include <iostream>
- #include <fstream>
- #include <sstream>
- #include <climits>
- #include <iomanip>
- #include <cstdio>
- #include <vector>
- #include <string>
- #include <stack>
- #include <queue>
- #include <deque>
- #include <bitset>
- #include <algorithm>
- #include <cmath>
- #include <set>
- #include <unordered_set>
- #include <map>
- #include <unordered_map>
- #include <chrono>
- #include <random>
- #include <complex>
- #include <numeric>
- #include <assert.h>
- using namespace std;
- using ll = long long;
- using ull = unsigned long long;
- using ui = unsigned int;
- using ld = long double;
- using pii = pair<int, int>;
- using pil = pair<int, long long>;
- using pli = pair<long long, int>;
- using pll = pair<long long, long long>;
- template <typename T>
- using uset = unordered_set<T>;
- template <typename T1, typename T2>
- using umap = unordered_map<T1, T2>;
- #define all(x) x.begin(), x.end()
- #define rall(x) x.rbegin(), x.rend()
- #ifdef _DEBUG
- const int lg = 7;
- const int NODES = 100;
- const int N = 100;
- const int Q = 200;
- #else
- const int lg = 11;
- const int NODES = 1e6 + 200;
- const int N = 5e5 + 10 + 26;
- const int Q = 6e6 + 10;
- #endif
- vector<int> g_sound[N];
- int used[N];
- int cmp[N];
- void dfs(int v) {
- used[v] = 1;
- for (int u : g_sound[v])
- if (!used[u]) {
- cmp[u] = cmp[v];
- dfs(u);
- }
- }
- struct node {
- vector<int> ladder;
- int to[26]{}, go[26]{};
- int up[lg]{};
- int par = 0, pch = 0, suf = 0, super = 0;
- int dep = 0, len = 0, term = 0;
- int mxd = 0;
- };
- node trie[NODES];
- int hbit[NODES];
- int get_term(int v) {
- return trie[v].term ? v : trie[v].super;
- }
- int LA(int v, int k) {
- if (!k)
- return v;
- if (trie[v].dep <= k)
- return 0;
- int h = hbit[k];
- v = trie[v].up[h];
- k -= 1 << h;
- int id = trie[trie[v].mxd].dep - trie[v].dep;
- id += k;
- return trie[trie[v].mxd].ladder[id];
- }
- int nv = 1;
- int ext() {
- return nv++;
- }
- void add(string &s, int x) {
- int v = 0;
- for (char cc : s) {
- int c = cc - 'a';
- if (!trie[v].to[c]) {
- trie[nv].par = v;
- trie[nv].pch = c;
- trie[nv].len = trie[v].len + 1;
- trie[v].to[c] = ext();
- }
- v = trie[v].to[c];
- }
- trie[v].term = x;
- }
- void aho_corasick() {
- vector<int> q(nv);
- int tail = 0, head = 0;
- q[tail++] = 0;
- while (head < tail) {
- int v = q[head++];
- if (v && trie[v].par) {
- trie[v].suf = trie[trie[trie[v].par].suf].go[trie[v].pch];
- if (trie[trie[v].suf].term)
- trie[v].super = trie[v].suf;
- else
- trie[v].super = trie[trie[v].suf].super;
- trie[v].up[0] = trie[v].super;
- trie[v].dep = trie[trie[v].super].dep;
- }
- if (trie[v].term) {
- trie[v].dep++;
- trie[v].up[0] = trie[v].super;
- }
- for (int c = 0; c < 26; c++) {
- if (trie[v].to[c]) {
- trie[v].go[c] = trie[v].to[c];
- q[tail++] = trie[v].to[c];
- } else {
- trie[v].go[c] = trie[trie[v].suf].go[c];
- }
- }
- }
- for (int i = nv - 1; i > -1; i--) {
- int v = q[i];
- if (!trie[v].mxd)
- trie[v].mxd = v;
- int dep = trie[trie[v].mxd].dep;
- if (trie[v].term) {
- trie[trie[v].mxd].ladder.push_back(v);
- int pr1 = trie[v].super;
- if (trie[trie[pr1].mxd].dep < dep)
- trie[pr1].mxd = trie[v].mxd;
- }
- }
- for (int i = 1; i < lg; i++)
- for (int j = 0; j < nv; j++)
- if (trie[j].term)
- trie[j].up[i] = trie[trie[j].up[i - 1]].up[i - 1];
- }
- const int mod1 = 1e9 + 7, mod2 = 1e9 + 9;
- int add(int a, int b, int mod) {
- if (a + b >= mod)
- return a + b - mod;
- return a + b;
- }
- int sub(int a, int b, int mod) {
- if (a < b)
- return a - b + mod;
- return a - b;
- }
- int mul(int a, int b, int mod) {
- return (ll)a * b % mod;
- }
- const int base1 = 1e6 + 3, base2 = 1e6 + 23;
- struct hint {
- int h1 = 0, h2 = 0;
- hint() {}
- hint(int h) : h1(h), h2(h) {}
- hint(int h1, int h2) : h1(h1), h2(h2) {}
- };
- hint operator+(const hint &a, const hint &b) {
- return { add(a.h1, b.h1, mod1), add(a.h2, b.h2, mod2) };
- }
- hint operator-(const hint &a, const hint &b) {
- return { sub(a.h1, b.h1, mod1), sub(a.h2, b.h2, mod2) };
- }
- hint operator*(const hint &a, const hint &b) {
- return { mul(a.h1, b.h1, mod1), mul(a.h2, b.h2, mod2) };
- }
- bool operator==(const hint &a, const hint &b) {
- return a.h1 == b.h1 && a.h2 == b.h2;
- }
- const hint base{ base1, base2 };
- hint pw[N];
- struct query {
- int l, r, i;
- };
- string t;
- pair<hint, int> hq[Q];
- pair<hint, int> slow_dp[1000][1000];
- vector<pii> del_edge[N];
- int pr[N];
- pair<hint, int> dsu_hash[N];
- int jump[N];
- vector<pii> buc_q[N];
- void compress(int a) {
- if (pr[a] == a)
- return;
- compress(pr[a]);
- dsu_hash[a].first = dsu_hash[a].first * pw[dsu_hash[pr[a]].second] + dsu_hash[pr[a]].first;
- dsu_hash[a].second += dsu_hash[pr[a]].second;
- pr[a] = pr[pr[a]];
- }
- void divide(int l, int r, vector<query> q) {
- if (q.empty())
- return;
- if (r - l <= 10) {
- for (int ri = l; ri <= r - 2; ri++) {
- int v = 0;
- for (int li = ri; li >= l; li--) {
- v = trie[v].go[t[li] - 'a'];
- int u = get_term(v);
- if (trie[u].len == ri - li + 1)
- slow_dp[li - l][ri + 1 - l] = { trie[u].term, 1 };
- else {
- auto &tmp = slow_dp[li - l + trie[u].len][ri + 1 - l];
- slow_dp[li - l][ri - l + 1].first = hint(trie[u].term) * pw[tmp.second] + tmp.first;
- slow_dp[li - l][ri - l + 1].second = 1 + tmp.second;
- }
- }
- }
- for (auto &qi : q) {
- auto &tmp = slow_dp[qi.l - l][qi.r - l];
- hq[qi.i].first = hq[qi.i].first * pw[tmp.second] + tmp.first;
- hq[qi.i].second += tmp.second;
- }
- return;
- }
- int m = (l + r) / 2;
- vector<query> ql, qr, tmp;
- for (auto &qi : q) {
- if (qi.r < m)
- ql.push_back(qi);
- else if (qi.l >= m)
- qr.push_back(qi);
- else
- tmp.push_back(qi);
- }
- divide(l, m, ql);
- ql.clear();
- if (!tmp.empty()) {
- for (int i = l; i < m; i++) {
- pr[i] = i;
- dsu_hash[i] = { 0, 0 };
- }
- for (int i = m; i < r; i++) {
- del_edge[i].clear();
- buc_q[i].clear();
- }
- for (auto &qi : tmp)
- buc_q[qi.r].push_back({ qi.l, qi.i });
- int v = 0, v1 = 0;
- for (int i = r - 2; i >= m - 1; i--)
- v1 = trie[v1].go[t[i] - 'a'];
- jump[m - 1] = get_term(v1);
- for (int i = m - 2; i >= l; i--) {
- v = trie[v].go[t[i] - 'a'];
- v1 = trie[v1].go[t[i] - 'a'];
- int u = get_term(v), u1 = get_term(v1);
- if (u == u1) {
- int j = i + trie[u].len;
- pr[i] = j;
- dsu_hash[i] = { trie[u].term, 1 };
- } else {
- jump[i] = u1;
- u1 = LA(u1, trie[u1].dep - trie[u].dep - 1);
- int j = i + trie[u1].len;
- if (j > m)
- del_edge[j].push_back({ i, u });
- }
- }
- for (int ri = r - 1; ri >= m; ri--) {
- for (auto &qi : buc_q[ri]) {
- compress(qi.first);
- hint h = dsu_hash[qi.first].first;
- int len = dsu_hash[qi.first].second;
- int from = pr[qi.first];
- int u = jump[from];
- if (trie[u].len > ri - from) {
- for (int i = lg - 1; i > -1; i--)
- if (trie[trie[u].up[i]].len > ri - from)
- u = trie[u].up[i];
- u = trie[u].super;
- }
- int to = from + trie[u].len;
- h = h * base + trie[u].term;
- len++;
- hq[qi.second].first = hq[qi.second].first * pw[len] + h;
- hq[qi.second].second += len;
- if (to < ri)
- qr.push_back({ to, ri, qi.second });
- }
- for (auto &p : del_edge[ri]) {
- int i = p.first;
- int u = p.second;
- pr[i] = i + trie[u].len;
- dsu_hash[i] = { trie[u].term, 1 };
- }
- }
- }
- tmp.clear();
- divide(m, r, qr);
- }
- inline void solve() {
- cin >> t;
- int n, k;
- cin >> n >> k;
- vector<string> s(n + 26);
- for (int i = 0; i < 26; i++)
- s[i] = (char)(i + 'a');
- for (int i = 0; i < n; i++) {
- cin >> s[i + 26];
- reverse(all(s[i + 26]));
- }
- for (int i = 0; i < k; i++) {
- int v, u;
- cin >> v >> u;
- v--;
- u--;
- g_sound[v].push_back(u);
- g_sound[u].push_back(v);
- }
- for (int v = 0; v < n + 26; v++)
- if (!used[v]) {
- cmp[v] = v + 1;
- dfs(v);
- }
- for (int v = 0; v < n + 26; v++)
- add(s[v], cmp[v]);
- aho_corasick();
- int queries;
- cin >> queries;
- vector<query> q(2 * queries);
- for (int i = 0; i < queries; i++) {
- int l1, r1, l2, r2;
- cin >> l1 >> r1 >> l2 >> r2;
- l1--;
- l2--;
- q[2 * i] = { l1, r1, 2 * i };
- q[2 * i + 1] = { l2, r2, 2 * i + 1 };
- }
- divide(0, t.size() + 1, q);
- for (int i = 0; i < 2 * queries; i += 2) {
- if (hq[i] == hq[i + 1])
- cout << "Yes\n";
- else
- cout << "No\n";
- }
- }
- signed main() {
- for (int i = 2; i < NODES; i++)
- hbit[i] = hbit[i >> 1] + 1;
- pw[0] = { 1, 1 };
- for (int i = 1; i < N; i++)
- pw[i] = pw[i - 1] * base;
- #ifdef _DEBUG
- freopen("01.dat", "r", stdin);
- #endif
- ios_base::sync_with_stdio(false);
- cin.tie(nullptr);
- cout.tie(nullptr);
- int tt = 1;
- #ifdef _DEBUG
- cin >> tt;
- #endif
- for (int test_id = 1; test_id <= tt; test_id++) {
- #ifdef _DEBUG
- cout << "TESTCASE #" << test_id << ":\n";
- #endif
- solve();
- }
- return 0;
- }
Advertisement
Add Comment
Please, Sign In to add comment