I题,线性时间构造,常量时间查询。 最优解?

#pragma GCC optimize("O2")
#pragma GCC optimize("O3")
#pragma GCC optimize("Ofast")
#pragma GCC optimize("unroll-loops")
#pragma GCC target("avx,avx2,fma")
#pragma GCC target("sse4,popcnt,abm,mmx")

#include <bits/stdc++.h>

#define out(x) cout << #x << '=' << (x) << endl
#define out2(x, y) cout << #x << '=' << (x) << ',' << #y << '=' << (y) << endl 
#define no do { cout << "No" << endl; return; } while(0)
#define yes do { cout << "Yes" << endl; return; } while (0)
#define lowbit(x) ((x) & -(x))

using namespace std;

using ll = long long;

const ll inf = 0x3f3f3f3f3f3f3f3fLL;
const int infi = 0x3f3f3f3f;

template<typename T> ostream & operator << (ostream &out,const set<T>&obj){out<<"set(";for(auto it=obj.begin();it!=obj.end();it++) out<<(it==obj.begin()?"":", ")<<*it;out<<")";return out;}
template<typename T1,typename T2> ostream & operator << (ostream &out,const map<T1,T2>&obj){out<<"map(";for(auto it=obj.begin();it!=obj.end();it++) out<<(it==obj.begin()?"":", ")<<it->first<<": "<<it->second;out<<")";return out;}
template<typename T1,typename T2> ostream & operator << (ostream &out,const pair<T1,T2>&obj){out<<"<"<<obj.first<<", "<<obj.second<<">";return out;}
template<typename T> ostream & operator << (ostream &out,const vector<T>&obj){out<<"vector(";for(auto it=obj.begin();it!=obj.end();it++) out<<(it==obj.begin()?"":", ")<<*it;out<<")";return out;}

namespace Fast_IO{ 
    const int MAXL((1 << 18) + 1);int iof, iotp;
    char ioif[MAXL], *ioiS, *ioiT, ioof[MAXL],*iooS=ioof,*iooT=ioof+MAXL-1,ioc,iost[55];
    char Getchar(){
        if (ioiS == ioiT){
            ioiS=ioif;ioiT=ioiS+fread(ioif,1,MAXL,stdin);return (ioiS == ioiT ? EOF : *ioiS++);
        }else return (*ioiS++);
    }
    void Write(){fwrite(ioof,1,iooS-ioof,stdout);iooS=ioof;}
    void Putchar(char x){*iooS++ = x;if (iooS == iooT)Write();}
    inline int read(){
        int x=0;for(iof=1,ioc=Getchar();(ioc<'0'||ioc>'9')&&ioc!=EOF;)iof=ioc=='-'?-1:1,ioc=Getchar();
        if(ioc==EOF)Write(),exit(0);
        for(x=0;ioc<='9'&&ioc>='0';ioc=Getchar())x=(x<<3)+(x<<1)+(ioc^48);return x*iof;
    }
    inline long long read_ll(){
        long long x=0;for(iof=1,ioc=Getchar();(ioc<'0'||ioc>'9')&&ioc!=EOF;)iof=ioc=='-'?-1:1,ioc=Getchar();
        if(ioc==EOF)Write(),exit(0);
        for(x=0;ioc<='9'&&ioc>='0';ioc=Getchar())x=(x<<3)+(x<<1)+(ioc^48);return x*iof;
    }
    void Getstr(char *s, int &l){
        for(ioc=Getchar();ioc==' '||ioc=='\n'||ioc=='\t';)ioc=Getchar();
        if(ioc==EOF)Write(),exit(0);
        for(l=0;!(ioc==' '||ioc=='\n'||ioc=='\t'||ioc==EOF);ioc=Getchar())s[l++]=ioc;s[l] = 0;
    }
    template <class Int>void Print(Int x, char ch = '\0'){
        if(!x)Putchar('0');if(x<0)Putchar('-'),x=-x;while(x)iost[++iotp]=x%10+'0',x/=10;
        while(iotp)Putchar(iost[iotp--]);if (ch)Putchar(ch);
    }
    void Putstr(const char *s){for(int i=0,n=strlen(s);i<n;++i)Putchar(s[i]);}
} // namespace Fast_IO
using namespace Fast_IO;

namespace SAIS {
#define SAIS_UCHAR_SIZE 256
#define SAIS_MINBUCKETSIZE 256
#define sais_index_type int
#define sais_bool_type int
#define SAIS_LMSSORT2_LIMIT 0x3fffffff
#define SAIS_MYMALLOC(_num, _type) ((_type *)malloc((_num) * sizeof(_type)))
#define chr(_a)                                                   \
    (cs == sizeof(sais_index_type) ? ((sais_index_type *)T)[(_a)] \
                                   : ((unsigned char *)T)[(_a)])
  inline void getCounts(const void *T, sais_index_type *C, sais_index_type n,
                        sais_index_type k, int cs) {
    sais_index_type i;
    for (i = 0; i < k; ++i) C[i] = 0;
    for (i = 0; i < n; ++i) ++C[chr(i)];
  } // getCounts
  inline void getBuckets(const sais_index_type *C, sais_index_type *B,
                         sais_index_type k, sais_bool_type end) {
    sais_index_type i, sum = 0;
    if (end) {
      for (i = 0; i < k; ++i) {
        sum += C[i];
        B[i] = sum;
      }
    } else {
      for (i = 0; i < k; ++i) {
        sum += C[i];
        B[i] = sum - C[i];
      }
    }
  } // getBuckets
  void LMSsort1(const void *T, sais_index_type *SA, sais_index_type *C,
                sais_index_type *B, sais_index_type n, sais_index_type k,
                int cs) {
    sais_index_type *b, i, j;
    sais_index_type c0, c1;
    if (C == B) getCounts(T, C, n, k, cs);
    getBuckets(C, B, k, 0);
    j = n - 1;
    b = SA + B[c1 = chr(j)];
    --j;
    *b++ = (chr(j) < c1) ? ~j : j;
    for (i = 0; i < n; ++i) {
      if (0 < (j = SA[i])) {
        if ((c0 = chr(j)) != c1) {
          B[c1] = b - SA;
          b = SA + B[c1 = c0];
        }
        --j;
        *b++ = (chr(j) < c1) ? ~j : j;
        SA[i] = 0;
      } else if (j < 0) SA[i] = ~j;
    }
    if (C == B) getCounts(T, C, n, k, cs);
    getBuckets(C, B, k, 1);
    for (i = n - 1, b = SA + B[c1 = 0]; 0 <= i; --i) {
      if (0 < (j = SA[i])) {
        if ((c0 = chr(j)) != c1) {
          B[c1] = b - SA;
          b = SA + B[c1 = c0];
        }
        --j;
        *--b = (chr(j) > c1) ? ~(j + 1) : j;
        SA[i] = 0;
      }
    }
  } // LMSsort1
  sais_index_type LMSpostproc1(const void *T, sais_index_type *SA,
                               sais_index_type n, sais_index_type m,
                               int cs) {
    sais_index_type i, j, p, q, plen, qlen, name;
    sais_index_type c0, c1;
    sais_bool_type diff;
    for (i = 0; (p = SA[i]) < 0; ++i) SA[i] = ~p;
    if (i < m) {
      for (j = i, ++i;; ++i) {
        if ((p = SA[i]) < 0) {
          SA[j++] = ~p;
          SA[i] = 0;
          if (j == m) break;
        }
      }
    }
    i = n - 1;
    j = n - 1;
    c0 = chr(n - 1);
    do c1 = c0;
    while ((0 <= --i) && ((c0 = chr(i)) >= c1));
    for (; 0 <= i;) {
      do c1 = c0;
      while ((0 <= --i) && ((c0 = chr(i)) <= c1));
      if (0 <= i) {
        SA[m + ((i + 1) >> 1)] = j - i;
        j = i + 1;
        do c1 = c0;
        while ((0 <= --i) && ((c0 = chr(i)) >= c1));
      }
    }
    for (i = 0, name = 0, q = n, qlen = 0; i < m; ++i) {
      p = SA[i], plen = SA[m + (p >> 1)], diff = 1;
      if ((plen == qlen) && ((q + plen) < n)) {
        for (j = 0; (j < plen) && (chr(p + j) == chr(q + j)); ++j) ;
        if (j == plen) diff = 0;
      }
      if (diff != 0) ++name, q = p, qlen = plen;
      SA[m + (p >> 1)] = name;
    }
    return name;
  } // LMSpostproc1
  void LMSsort2(const void *T, sais_index_type *SA, sais_index_type *C,
                sais_index_type *B, sais_index_type *D, sais_index_type n,
                sais_index_type k, int cs) {
    sais_index_type *b, i, j, t, d;
    sais_index_type c0, c1;
    getBuckets(C, B, k, 0);
    j = n - 1;
    b = SA + B[c1 = chr(j)];
    --j;
    t = (chr(j) < c1);
    j += n;
    *b++ = (t & 1) ? ~j : j;
    for (i = 0, d = 0; i < n; ++i) {
      if (0 < (j = SA[i])) {
        if (n <= j) d += 1, j -= n;
        if ((c0 = chr(j)) != c1) {
          B[c1] = b - SA;
          b = SA + B[c1 = c0];
        }
        --j;
        t = c0;
        t = (t << 1) | (chr(j) < c1);
        if (D[t] != d) j += n, D[t] = d;
        *b++ = (t & 1) ? ~j : j;
        SA[i] = 0;
      } else if (j < 0) SA[i] = ~j;
    }
    for (i = n - 1; 0 <= i; --i) {
      if (0 < SA[i]) {
        if (SA[i] < n) {
          SA[i] += n;
          for (j = i - 1; SA[j] < n; --j) ;
          SA[j] -= n;
          i = j;
        }
      }
    }
    getBuckets(C, B, k, 1);
    for (i = n - 1, d += 1, b = SA + B[c1 = 0]; 0 <= i; --i) {
      if (0 < (j = SA[i])) {
        if (n <= j) d += 1, j -= n;
        if ((c0 = chr(j)) != c1) {
          B[c1] = b - SA;
          b = SA + B[c1 = c0];
        }
        --j;
        t = c0;
        t = (t << 1) | (chr(j) > c1);
        if (D[t] != d) j += n, D[t] = d;
        *--b = (t & 1) ? ~(j + 1) : j;
        SA[i] = 0;
      }
    }
  } // LMSsort2
  sais_index_type LMSpostproc2(sais_index_type *SA, sais_index_type n, sais_index_type m) {
    sais_index_type i, j, d, name;
    for (i = 0, name = 0; (j = SA[i]) < 0; ++i) {
      j = ~j;
      if (n <= j) name += 1;
      SA[i] = j;
    }
    if (i < m) {
      for (d = i, ++i;; ++i) {
        if ((j = SA[i]) < 0) {
          j = ~j;
          if (n <= j) name += 1;
          SA[d++] = j;
          SA[i] = 0;
          if (d == m) break;
        }
      }
    }
    if (name < m) {
      for (i = m - 1, d = name + 1; 0 <= i; --i) {
        if (n <= (j = SA[i])) j -= n, --d;
        SA[m + (j >> 1)] = d;
      }
    } else {
      for (i = 0; i < m; ++i)
        if (n <= (j = SA[i])) j -= n, SA[i] = j;
    }
    return name;
  } // LMSpostproc2
  void induceSA(const void *T, sais_index_type *SA, sais_index_type *C,
                sais_index_type *B, sais_index_type n, sais_index_type k,
                int cs) {
    sais_index_type *b, i, j;
    sais_index_type c0, c1;
    if (C == B) getCounts(T, C, n, k, cs);
    getBuckets(C, B, k, 0);
    j = n - 1;
    b = SA + B[c1 = chr(j)];
    *b++ = ((0 < j) && (chr(j - 1) < c1)) ? ~j : j;
    for (i = 0; i < n; ++i) {
      j = SA[i], SA[i] = ~j;
      if (0 < j) {
        --j;
        if ((c0 = chr(j)) != c1) {
          B[c1] = b - SA;
          b = SA + B[c1 = c0];
        }
        *b++ = ((0 < j) && (chr(j - 1) < c1)) ? ~j : j;
      }
    }
    if (C == B) getCounts(T, C, n, k, cs);
    getBuckets(C, B, k, 1);
    for (i = n - 1, b = SA + B[c1 = 0]; 0 <= i; --i) {
      if (0 < (j = SA[i])) {
        --j;
        if ((c0 = chr(j)) != c1) {
          B[c1] = b - SA;
          b = SA + B[c1 = c0];
        }
        *--b = ((j == 0) || (chr(j - 1) > c1)) ? ~j : j;
      } else SA[i] = ~j;
    }
  } // induceSA
  sais_index_type computeBWT(const void *T, sais_index_type *SA,
                             sais_index_type *C, sais_index_type *B,
                             sais_index_type n, sais_index_type k,
                             int cs) {
    sais_index_type *b, i, j, pidx = -1;
    sais_index_type c0, c1;
    if (C == B) getCounts(T, C, n, k, cs);
    getBuckets(C, B, k, 0);
    j = n - 1;
    b = SA + B[c1 = chr(j)];
    *b++ = ((0 < j) && (chr(j - 1) < c1)) ? ~j : j;
    for (i = 0; i < n; ++i) {
      if (0 < (j = SA[i])) {
        --j;
        SA[i] = ~((sais_index_type)(c0 = chr(j)));
        if (c0 != c1) {
          B[c1] = b - SA;
          b = SA + B[c1 = c0];
        }
        *b++ = ((0 < j) && (chr(j - 1) < c1)) ? ~j : j;
      } else if (j != 0) SA[i] = ~j;
    }
    if (C == B) getCounts(T, C, n, k, cs);
    getBuckets(C, B, k, 1);
    for (i = n - 1, b = SA + B[c1 = 0]; 0 <= i; --i) {
      if (0 < (j = SA[i])) {
        --j;
        SA[i] = (c0 = chr(j));
        if (c0 != c1) {
          B[c1] = b - SA;
          b = SA + B[c1 = c0];
        }
        *--b = ((0 < j) && (chr(j - 1) > c1)) ? ~((sais_index_type)chr(j - 1)) : j;
      } else if (j != 0) SA[i] = ~j;
      else pidx = i;
    }
    return pidx;
  } // computeBWT
  sais_index_type sais_main(const void *T, sais_index_type *SA,
                            sais_index_type fs, sais_index_type n,
                            sais_index_type k, int cs, sais_bool_type isbwt) {
    sais_index_type *C, *B, *D, *RA, *b;
    sais_index_type i, j, m, p, q, t, name, pidx = 0, newfs;
    sais_index_type c0, c1;
    unsigned int flags;
    if (k <= SAIS_MINBUCKETSIZE) {
      if ((C = SAIS_MYMALLOC(k, sais_index_type)) == NULL) return -2;
      if (k <= fs) {
        B = SA + (n + fs - k);
        flags = 1;
      } else {
        if ((B = SAIS_MYMALLOC(k, sais_index_type)) == NULL) {
          free(C);
          return -2;
        }
        flags = 3;
      }
    } else if (k <= fs) {
      C = SA + (n + fs - k);
      if (k <= (fs - k)) {
        B = C - k;
        flags = 0;
      } else if (k <= (SAIS_MINBUCKETSIZE * 4)) {
        if ((B = SAIS_MYMALLOC(k, sais_index_type)) == NULL) return -2;
        flags = 2;
      } else {
        B = C;
        flags = 8;
      }
    } else {
      if ((C = B = SAIS_MYMALLOC(k, sais_index_type)) == NULL) return -2;
      flags = 4 | 8;
    }
    if ((n <= SAIS_LMSSORT2_LIMIT) && (2 <= (n / k))) {
      if (flags & 1) flags |= ((k * 2) <= (fs - k)) ? 32 : 16;
      else if ((flags == 0) && ((k * 2) <= (fs - k * 2))) flags |= 32;
    }
    getCounts(T, C, n, k, cs);
    getBuckets(C, B, k, 1);
    for (i = 0; i < n; ++i) SA[i] = 0;
    b = &t; i = n - 1; j = n; m = 0; c0 = chr(n - 1);
    do c1 = c0;
    while ((0 <= --i) && ((c0 = chr(i)) >= c1));
    for (; 0 <= i;) {
      do c1 = c0;
      while ((0 <= --i) && ((c0 = chr(i)) <= c1));
      if (0 <= i) {
        *b = j;
        b = SA + --B[c1];
        j = i;
        ++m;
        do c1 = c0;
        while ((0 <= --i) && ((c0 = chr(i)) >= c1));
      }
    }
    if (1 < m) {
      if (flags & (16 | 32)) {
        if (flags & 16) {
          if ((D = SAIS_MYMALLOC(k * 2, sais_index_type)) == NULL) {
            if (flags & (1 | 4)) free(C);
            if (flags & 2) free(B);
            return -2;
          }
        } else D = B - k * 2;
        ++B[chr(j + 1)];
        for (i = 0, j = 0; i < k; ++i) {
          j += C[i];
          if (B[i] != j) SA[B[i]] += n;
          D[i] = D[i + k] = 0;
        }
        LMSsort2(T, SA, C, B, D, n, k, cs);
        name = LMSpostproc2(SA, n, m);
        if (flags & 16) free(D);
      } else {
        LMSsort1(T, SA, C, B, n, k, cs);
        name = LMSpostproc1(T, SA, n, m, cs);
      }
    } else if (m == 1) {
      *b = j + 1;
      name = 1;
    } else name = 0;
    if (name < m) {
      if (flags & 4) free(C);
      if (flags & 2) free(B);
      newfs = (n + fs) - (m * 2);
      if ((flags & (1 | 4 | 8)) == 0) {
        if ((k + name) <= newfs) newfs -= k;
        else flags |= 8;
      }
      RA = SA + m + newfs;
      for (i = m + (n >> 1) - 1, j = m - 1; m <= i; --i)
        if (SA[i] != 0) RA[j--] = SA[i] - 1;
      if (sais_main(RA, SA, newfs, m, name, sizeof(sais_index_type), 0) != 0) {
        if (flags & 1) free(C);
        return -2;
      }
      i = n - 1;
      j = m - 1;
      c0 = chr(n - 1);
      do c1 = c0;
      while ((0 <= --i) && ((c0 = chr(i)) >= c1));
      for (; 0 <= i;) {
        do c1 = c0;
        while ((0 <= --i) && ((c0 = chr(i)) <= c1));
        if (0 <= i) {
          RA[j--] = i + 1;
          do c1 = c0;
          while ((0 <= --i) && ((c0 = chr(i)) >= c1));
        }
      }
      for (i = 0; i < m; ++i) SA[i] = RA[SA[i]];
      if (flags & 4)
        if ((C = B = SAIS_MYMALLOC(k, int)) == NULL) return -2;
      if (flags & 2) {
        if ((B = SAIS_MYMALLOC(k, int)) == NULL) {
          if (flags & 1) free(C);
          return -2;
        }
      }
    }
    if (flags & 8) getCounts(T, C, n, k, cs);
    if (1 < m) {
      getBuckets(C, B, k, 1);
      i = m - 1, j = n, p = SA[m - 1], c1 = chr(p);
      do {
        q = B[c0 = c1];
        while (q < j) SA[--j] = 0;
        do {
          SA[--j] = p;
          if (--i < 0) break;
          p = SA[i];
        } while ((c1 = chr(p)) == c0);
      } while (0 <= i);
      while (0 < j) SA[--j] = 0;
    }
    if (isbwt == 0) induceSA(T, SA, C, B, n, k, cs);
    else pidx = computeBWT(T, SA, C, B, n, k, cs);
    if (flags & (1 | 4)) free(C);
    if (flags & 2) free(B);
    return pidx;
  } // sais_main
  __attribute__((__always_inline__))
  inline int sais(int n, const unsigned char *T, int *SA) {
    if ((T == NULL) || (SA == NULL) || (n < 0)) return -1;
    if (n <= 1) {
      if (n == 1) SA[0] = 0;
      return 0;
    }
    return sais_main(T, SA, 0, n, SAIS_UCHAR_SIZE, sizeof(unsigned char), 0);
  } // sais
 template<typename _Integer>
  int sais(int n, const _Integer *T, int k, int *SA) {
    if ((T == NULL) || (SA == NULL) || (n < 0) || (k <= 0)) return -1;
    if (n <= 1) {
      if (n == 1) SA[0] = 0;
      return 0;
    }
    return sais_main(T, SA, 0, n, k, sizeof(_Integer), 0);
  } // sais
#undef SAIS_UCHAR_SIZE
#undef SAIS_MINBUCKETSIZE
#undef sais_index_type
#undef sais_bool_type
#undef SAIS_LMSSORT2_LIMIT
#undef SAIS_MYMALLOC
#undef chr
} // namespace SAIS

using SAIS::sais;

template<typename _Integer>
int compute_lcp(int n, const _Integer *T, const int *sa, int *rk, int *lcp) {
  if ((T == NULL) || (sa == NULL) || (rk == NULL) || (lcp == NULL) || (n < 0)) return -1;
  for (int i = 0; i < n; ++i) rk[sa[i]] = i;
  for (int i = 0, j = 0; i <= n; ++i) {
    if (rk[i]) {
      if (j) --j;
      for (; T[sa[rk[i]] + j] == T[sa[rk[i] - 1] + j]; ++j);
      lcp[rk[i]] = j;
    }
  }
  return 0;
} // compute_lcp

const int N = 1e6;
int sa[N], rk[N], ht[N];

const int B = 20;
int lg[(N - 1) / B + 1 + 1], st[(N - 1) / B + 1][B], pr[N];

void compute_lcp_rmq(int n) {
    const int SZ = (n - 1) / B + 1;
    for (int i = 2; i <= SZ; i++) lg[i] = lg[i / 2] + 1;
    stack<int> stk;
    int val = 0;
    for (int i = 0; i < n; i++) {
        if (i % B == 0) {
            st[i / B][0] = ht[i];
            while (!stk.empty()) stk.pop();
            val = 0;
        } else {
            st[i / B][0] = min(st[i / B][0], ht[i]);
        }
        while (!stk.empty() && ht[stk.top()] >= ht[i]) {
            val ^= 1 << (stk.top() % B);
            stk.pop();
        }
        val |= 1 << (i % B);
        stk.push(i);
        pr[i] = val;
    }
    for (int i = 1; i <= lg[SZ]; i++) {
        for (int j = 0; j + (1 << i) - 1 < SZ; j++) {
            st[j][i] = min(st[j][i - 1], st[j + (1 << (i - 1))][i - 1]);
        }
    }
}

int lcp_full_block(int l, int r) {
    if (l > r) return infi;
    l /= B;
    r /= B;
    int len = r - l + 1;
    return min(st[l][lg[len]], st[r - (1 << lg[len]) + 1][lg[len]]);
}

int lcp_in_block(int l, int r) {
    return ht[__builtin_ctz(pr[r] >> (l % B)) + l];
}

int lcp(const int i, const int j) {
    if (i == j) out(":(");
    int l = rk[i], r = rk[j];
    if (l > r) swap(l, r);
    l++;
    if (l / B == r / B) return lcp_in_block(l, r);
    
    int lb = l + (((B - l) % B) + B) % B;
    int rb = r - (((r - (B - 1)) % B) + B) % B;
    
    int lcp = lcp_full_block(lb, rb);
    
    if (l != lb) lcp = min(lcp, lcp_in_block(l, lb - 1));
    if (r != rb) lcp = min(lcp, lcp_in_block(rb + 1, r));
    return lcp;
}

char s1[N], s2[N], s3[N];

void solve() {
    int n, m, q;
    n = read(), m = read(), q = read();
    //out(1 << B);
    Getstr(s1, n);
    Getstr(s2, m);
    for (int i = 1; i <= n; i++) s3[i] = s1[i - 1];
    for (int i = n + 1; i <= n + m; i++) s3[i] = s2[i - n - 1];
    sais(n + m + 1, (const unsigned char *) &s3, sa);
	compute_lcp(n + m + 1, (const unsigned char *) &s3, sa, rk, ht);
	compute_lcp_rmq(n + m + 1);
	for (int i = 1; i <= q; i++) {
	    int l1, r1, l2, r2;
	    l1 = read(), r1 = read(), l2 = read(), r2 = read();
	    int l = lcp(l1, n + l2);
	    //out(l);
	    if (l >= (r1 - l1 + 1)) {
	        Putchar('=');
	        Putchar('\n');
	    } else {
	        Putchar("<>"[s1[l1 + l - 1] > s2[l2 + l - 1]]);
	        Putchar('\n');
	    }
	}
	Write();
}

int main(void) {
    ios::sync_with_stdio(false);
    cin.tie(0); cout.tie(0);
    int t = 1;
	//cin >> t;
    
    while (t--) {
    	solve(); 
	}
}