Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #include <bits/stdc++.h>
- #define forn(i, n) for (int i = 0; i < int(n); i++)
- #define nfor(i, n) for (int i = int(n) - 1; i >= 0; i--)
- #define fore(i, l, r) for (int i = int(l); i < int(r); i++)
- #define correct(x, y, n, m) (0 <= (x) && (x) < (n) && 0 <= (y) && (y) < (m))
- #define all(a) (a).begin(), (a).end()
- #define sz(a) int((a).size())
- #define pb(a) push_back(a)
- #define mp(x, y) make_pair((x), (y))
- #define x first
- #define y second
- using namespace std;
- typedef long long li;
- typedef long double ld;
- typedef pair<int, int> pti;
- template<typename X> inline X abs(const X& a) { return a < 0? -a: a; }
- template<typename X> inline X sqr(const X& a) { return a * a; }
- template<typename A, typename B> inline ostream& operator<< (ostream& out, const pair<A, B>& p) { return out << "(" << p.x << ", " << p.y << ")"; }
- template<typename T> inline ostream& operator<< (ostream& out, const vector<T>& a) { out << "["; forn(i, sz(a)) { if (i) out << ','; out << ' ' << a[i]; } return out << " ]"; }
- template<typename T> inline ostream& operator<< (ostream& out, const set<T>& a) { return out << vector<T>(all(a)); }
- template<typename X, typename Y> inline ostream& operator<< (ostream& out, const map<X, Y>& a) { return out << vector<pair<X, Y>>(all(a)); }
- template<typename T> inline ostream& operator<< (ostream& out, pair<T*, int> a) { return out << vector<T>(a.x, a.x + a.y); }
- inline ld gett() { return ld(clock()) / CLOCKS_PER_SEC; }
- const int INF = int(1e9);
- const li INF64 = li(1e18);
- const ld EPS = 1e-9, PI = 3.1415926535897932384626433832795;
- const int N = 500500, M = 50500, Q = 500500;
- int n, m, k;
- char str[N];
- char buf[M];
- string a[M];
- pair<pti, pti> q[Q];
- bool read() {
- if (!gets(str)) return false;
- n = int(strlen(str));
- if (!n) return false;
- assert(cin >> m);
- forn(i, m) {
- assert(scanf("%s", buf) == 1);
- a[i] = string(buf);
- }
- assert(cin >> k);
- forn(i, k) {
- assert(scanf("%d%d%d%d", &q[i].y.x, &q[i].y.y, &q[i].x.x, &q[i].x.y) == 4);
- q[i].x.x--;
- q[i].y.x--;
- }
- return true;
- }
- struct node {
- int l, r;
- int parent, link;
- map<int, int> next;
- node(int l = 0, int r = 0, int parent = 0): l(l), r(r), parent(parent) {
- link = -1;
- next.clear();
- }
- };
- struct state {
- int v, pos;
- state(int v = 0, int pos = 0): v(v), pos(pos) { }
- };
- const int L = N + 2 * M, S = 200, V = 2 * L, LOGV = 20;
- int l;
- int s[L];
- int tsz = 1;
- node t[V];
- state ptr;
- inline int len(int v) { return t[v].r - t[v].l; }
- inline int split(state st) {
- if (st.pos == 0) return t[st.v].parent;
- if (st.pos == len(st.v)) return st.v;
- int cur = tsz++;
- assert(cur < V);
- t[cur] = node(t[st.v].l, t[st.v].l + st.pos, t[st.v].parent);
- t[cur].next[s[t[st.v].l + st.pos]] = st.v;
- t[t[st.v].parent].next[s[t[st.v].l]] = cur;
- t[st.v].parent = cur;
- t[st.v].l += st.pos;
- return cur;
- }
- state go(state st, int l, int r) {
- while (l < r) {
- if (st.pos == len(st.v)) {
- if (!t[st.v].next.count(s[l])) return state(-1, -1);
- st = state(t[st.v].next[s[l]], 0);
- } else {
- if (s[t[st.v].l + st.pos] != s[l]) return state(-1, -1);
- int d = min(len(st.v) - st.pos, r - l);
- l += d;
- st.pos += d;
- }
- }
- return st;
- }
- int link(int v) {
- int& ans = t[v].link;
- if (ans != -1) return ans;
- if (v == 0) return ans = 0;
- int p = t[v].parent;
- return ans = split(go(state(link(p), len(link(p))), t[v].l + (p == 0), t[v].r));
- }
- inline void treeExtand(int i) {
- while (true) {
- state next = go(ptr, i, i + 1);
- if (next.v != -1) {
- ptr = next;
- break;
- }
- int mid = split(ptr), cur = tsz++;
- assert(cur < V);
- t[cur] = node(i, l, mid);
- t[mid].next[s[i]] = cur;
- if (mid == 0) break;
- ptr = state(link(mid), len(link(mid)));
- }
- }
- vector<int> sharpPos;
- void prepareSuffixTree() {
- l = 0;
- t[0] = node();
- tsz = 1;
- sharpPos.clear();
- sharpPos.reserve(m + 1);
- forn(i, n) s[l++] = (int) str[i];
- sharpPos.pb(l);
- s[l++] = S;
- forn(i, m) {
- forn(j, sz(a[i]))
- s[l++] = (int) a[i][j];
- sharpPos.pb(l);
- s[l++] = S + i + 1;
- }
- forn(i, l) treeExtand(i);
- }
- int p[LOGV][V], pd[LOGV][V];
- int getParent(int v, int d) {
- nfor(i, LOGV)
- if (pd[i][v] <= d) {
- d -= pd[i][v];
- v = p[i][v];
- }
- return v;
- }
- void prepareBinaryLifts() {
- forn(i, tsz) {
- p[0][i] = t[i].parent;
- pd[0][i] = len(i);
- }
- fore(i, 1, LOGV)
- forn(j, tsz) {
- p[i][j] = p[i - 1][p[i - 1][j]];
- pd[i][j] = pd[i - 1][j] + pd[i - 1][p[i - 1][j]];
- }
- }
- state sufPos[N];
- void dfs1(int v, int d) {
- int idx = int(lower_bound(all(sharpPos), t[v].l) - sharpPos.begin());
- if (idx < sz(sharpPos) && sharpPos[idx] < t[v].r) {
- if (idx == 0) {
- int len = sharpPos[idx] - t[v].l;
- d += len;
- assert(d <= n);
- sufPos[n - d] = state(v, len);
- }
- return;
- }
- d += len(v);
- for (auto e : t[v].next)
- dfs1(e.y, d);
- }
- int getv(int l, int r) {
- int v = sufPos[l].v;
- int extra = len(v) - sufPos[l].pos;
- return getParent(v, (n - r) + extra);
- }
- state go(string str) {
- state st(0, 0);
- forn(i, sz(str)) {
- int c = (int) str[i];
- if (st.pos == len(st.v)) {
- assert(t[st.v].next.count(c));
- st = state(t[st.v].next[c], 0);
- }
- assert(s[t[st.v].l + st.pos] == c);
- st.pos++;
- }
- return st;
- }
- void prepareSuffixes() {
- dfs1(0, 0);
- #ifdef CHECK
- forn(i, n) {
- state st(0, 0);
- fore(j, i, n) {
- state st = go(string(str + i, str + j + 1));
- //cerr << "st.v=" << st.v << " getv(i, j + 1)=" << getv(i, j + 1) << endl;
- assert(st.v == getv(i, j + 1));
- }
- }
- #endif
- }
- struct ctnode {
- int key, prior;
- int val;
- int cnt;
- pti maxv;
- ctnode *l, *r;
- };
- typedef ctnode* tree;
- void printRec(tree t) {
- if (!t) return;
- printRec(t->l);
- cerr << mp(t->key, t->val) << ' ';
- printRec(t->r);
- }
- void print(tree t) {
- printRec(t);
- cerr << endl;
- }
- inline int getCnt(tree t) { return t ? t->cnt : 0; }
- inline pti getMax(tree t) { return t ? t->maxv : mp(-1, -1); }
- inline void lift(tree t) {
- if (!t) return;
- t->cnt = getCnt(t->l) + 1 + getCnt(t->r);
- t->maxv = mp(t->val, -t->key);
- if (t->l) t->maxv = max(t->maxv, t->l->maxv);
- if (t->r) t->maxv = max(t->maxv, t->r->maxv);
- }
- void split(tree t, int key, tree& t1, tree& t2) {
- if (!t) return void(t1 = t2 = NULL);
- if (key < t->key) {
- t2 = t;
- split(t2->l, key, t1, t2->l);
- lift(t2);
- } else {
- t1 = t;
- split(t1->r, key, t1->r, t2);
- lift(t1);
- }
- }
- tree merge(tree t1, tree t2) {
- if (!t1) return t2;
- if (!t2) return t1;
- if (t1->prior > t2->prior) {
- t1->r = merge(t1->r, t2);
- lift(t1);
- return t1;
- }
- t2->l = merge(t1, t2->l);
- lift(t2);
- return t2;
- }
- inline int myRand() { return abs((rand() << 16) ^ rand()); }
- const int HS = 2 * V;
- queue<int> heappos;
- ctnode heap[HS];
- void traverse(tree t, vector<pti>& vs) {
- if (!t) return;
- traverse(t->l, vs);
- vs.pb(mp(t->key, t->val));
- traverse(t->r, vs);
- heappos.push(int(t - heap));
- }
- inline void inc(tree& t, int key, int val) {
- tree t1, t2, t3, t4;
- split(t, key, t1, t2);
- split(t1, key - 1, t3, t4);
- if (!t4) {
- assert(!heappos.empty());
- int pos = heappos.front();
- heappos.pop();
- t4 = &heap[pos];
- t4->key = key;
- t4->prior = myRand();
- t4->val = 0;
- t4->l = t4->r = NULL;
- }
- t4->val += val;
- lift(t4);
- t = merge(merge(t3, t4), t2);
- }
- inline pti getMax(tree& t, int l, int r) {
- tree t1, t2, t3, t4;
- split(t, r - 1, t1, t2);
- split(t1, l - 1, t3, t4);
- pti ans = getMax(t4);
- t = merge(merge(t3, t4), t2);
- return ans;
- }
- tree mergeSTL(tree a, tree b) {
- if (getCnt(a) < getCnt(b)) swap(a, b);
- vector<pti> bb;
- bb.reserve(getCnt(b));
- traverse(b, bb);
- for (auto p : bb)
- inc(a, p.x, p.y);
- return a;
- }
- pti ans[Q];
- vector<int> queries[V];
- tree dfs2(int v) {
- tree res = NULL;
- int idx = int(lower_bound(all(sharpPos), t[v].l) - sharpPos.begin());
- //cerr << "v=" << v << " t[v].l=" << t[v].l << " t[v].r=" << t[v].r << " idx=" << idx << " sharpPos[idx]=" << sharpPos[idx] << endl;
- if (idx < sz(sharpPos) && sharpPos[idx] < t[v].r) {
- if (idx > 0) {
- //cerr << "idx-1=" << idx - 1 << endl;
- inc(res, idx - 1, +1);
- assert(queries[v].empty());
- }
- return res;
- }
- for (auto e : t[v].next) {
- tree nt = dfs2(e.y);
- res = mergeSTL(res, nt);
- }
- for (int idx : queries[v]) {
- pti p = getMax(res, q[idx].y.x, q[idx].y.y);
- p.y *= -1;
- if (p.x == -1) p = mp(0, q[idx].y.x);
- swap(p.x, p.y);
- //cerr << "idx=" << idx << " p=" << p << endl;
- ans[idx] = p;
- }
- //cerr << "v=" << v << endl;
- //print(res);
- return res;
- }
- void processQueries() {
- while (!heappos.empty()) heappos.pop();
- forn(i, HS) heappos.push(i);
- forn(i, tsz) queries[i].clear();
- forn(i, k) {
- int v = getv(q[i].x.x, q[i].x.y);
- queries[v].pb(i);
- ans[i] = mp(-1, -1);
- }
- dfs2(0);
- //cerr << "s: " << mp(s, l) << endl;
- //cerr << "sharpPos: " << sharpPos << endl;
- forn(i, k) {
- if (ans[i] == mp(-1, -1)) ans[i] = mp(q[i].y.x, 0);
- printf("%d %d\n", ans[i].x + 1, ans[i].y);
- }
- }
- void solve() {
- prepareSuffixTree();
- prepareBinaryLifts();
- prepareSuffixes();
- processQueries();
- }
- int main() {
- #ifdef SU1
- assert(freopen("input.txt", "rt", stdin));
- //assert(freopen("output.txt", "wt", stdout));
- #endif
- cout << setprecision(10) << fixed;
- cerr << setprecision(5) << fixed;
- while (read()) {
- ld stime = gett();
- solve();
- cerr << "Time: " << gett() - stime << endl;
- //break;
- }
- return 0;
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement