Problem p02250 (C++) — buggy submission, verdict: Time Limit Exceeded

#include <algorithm>
#include <cstdio>
#include <cstdlib>
#include <iostream>
#include <string>
#include <vector>

#define REP(i, n) for (int i = 0; i < int(n); ++i)
#define REPV(i, v, n) for (int i = 0, tmp = v; i < int(n); ++i)
#define FOR(i, a, b) for (int i = int(a); i < int(b); ++i)
#define DWN(i, b, a) for (int i = int(b - 1); i >= int(a); --i)

using namespace std;

typedef unsigned char byte;

byte mask[] = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01};
#define tget(i) !!(t[(i) >> 3] & mask[(i)&7])
#define tset(i, b)                                                             \\
  t[(i) >> 3] =                                                                \\
      (b) ? (mask[(i)&7] | t[(i) >> 3]) : ((~mask[(i)&7]) & t[(i) >> 3])
#define chr(i) (cs == sizeof(int) ? ((int *)s)[i] : ((byte *)s)[i])
#define isLMS(i) (i > 0 && tget(i) && !tget(i - 1))

void getBuckets(byte *s, int *bkt, int n, int K, int cs, bool end = true) {
  fill(bkt, bkt + K + 1, 0);
  REP(i, n) bkt[chr(i)]++;
  REPV(i, 0, K + 1) tmp += bkt[i], bkt[i] = end ? tmp : tmp - bkt[i];
}

void induceSAl(byte *t, int *SA, byte *s, int *bkt, int n, int K, int cs,
               bool end = false) {
  getBuckets(s, bkt, n, K, cs, end);
  REP(i, n)
  if (SA[i] > 0 && !tget(SA[i] - 1)) SA[bkt[chr(SA[i] - 1)]++] = SA[i] - 1;
}

void induceSAs(byte *t, int *SA, byte *s, int *bkt, int n, int K, int cs,
               bool end = true) {
  getBuckets(s, bkt, n, K, cs, end);
  DWN(i, n, 0)
  if (SA[i] > 0 && tget(SA[i] - 1)) SA[--bkt[chr(SA[i] - 1)]] = SA[i] - 1;
}

void SA_IS(byte *s, int *SA, int n, int K = 128, int cs = 1) {
  byte t[(n >> 3) + 1];
  int bkt[K + 1], n1 = 0, name = 0;

  tset(n - 2, 0), tset(n - 1, 1);
  DWN(i, n - 2, 0)
  tset(i, (chr(i) < chr(i + 1) || (chr(i) == chr(i + 1) && tget(i + 1))));
  getBuckets(s, bkt, n, K, cs);
  fill(SA, SA + n, -1);
  FOR(i, 1, n) if (isLMS(i)) SA[--bkt[chr(i)]] = i;

  induceSAl(t, SA, s, bkt, n, K, cs);
  induceSAs(t, SA, s, bkt, n, K, cs);

  REP(i, n) if (isLMS(SA[i])) SA[n1++] = SA[i];
  fill(SA + n1, SA + n, -1);

  REPV(i, -1, n1) {
    int pos = SA[i], diff = false;
    for (int d = 0; d < n && !diff; d++) {
      diff = chr(pos + d) != chr(tmp + d) || tget(pos + d) != tget(tmp + d);
      if (!diff && d && (isLMS(pos + d) || isLMS(tmp + d)))
        break;
    }
    if (diff)
      name++, tmp = pos;
    SA[n1 + ((pos - (pos & 1)) >> 1)] = name - 1;
  }
  int *s1 = SA + n - n1;
  for (int i = n - 1, j = n - 1; i >= n1; i--)
    if (SA[i] >= 0)
      SA[j--] = SA[i];
  if (name < n1)
    SA_IS((byte *)s1, SA, n1, name - 1, sizeof(int));
  else
    REP(i, n1) SA[s1[i]] = i;

  getBuckets(s, bkt, n, K, cs);
  for (int i = 1, j = 0; i < n; i++)
    if (isLMS(i))
      s1[j++] = i;
  REP(i, n1) SA[i] = s1[SA[i]];
  fill(SA + n1, SA + n, -1);

  DWN(i, n1, 0) {
    int tmp = SA[i];
    SA[i] = -1, SA[--bkt[chr(tmp)]] = tmp;
  }
  induceSAl(t, SA, s, bkt, n, K, cs);
  induceSAs(t, SA, s, bkt, n, K, cs);
}

const int maxn = 1000001;
int n, sa[maxn];

bool contain(string S, int *sa, string T) {
  int a = 0, b = S.length();
  while (b - a > 1) {
    int c = (a + b) / 2;
    if (S.compare(sa[c], T.length(), T) < 0)
      a = c;
    else
      b = c;
  }
  return S.compare(sa[b], T.length(), T) == 0;
}

char a[maxn], b[maxn];

int main(void) {
  int q;
  scanf("%s", a);
  string s = string(a);
  SA_IS((byte *)s.c_str(), sa, s.size() + 1);

  scanf("%d", &q);
  while (q--) {
    scanf("%s", b);
    if (contain(s, sa, string(b)))
      printf("1\\n");
    else
      printf("0\\n");
  }

  return 0;
}

Error: TLE

Fixed submission:

#include <algorithm>
#include <iostream>
#include <string>
#include <vector>

#define REP(i, n) for (int i = 0; i < int(n); ++i)
#define ALL(A) (A).begin(), (A).end()
#define SZ(A) int(A.size())

using namespace std;

typedef unsigned long long ull;

struct RollingHash {
  static const ull p = 100000007;
  string s;
  int n;
  vector<ull> pow, phash;

  RollingHash(string s) : s(s), n(SZ(s)), pow(n + 1), phash(n + 1) {
    pow[0] = 1, phash[0] = 0;
    REP(i, n) {
      phash[i + 1] = s[i] + phash[i] * p;
      pow[i + 1] = pow[i] * p;
    }
  }

  bool operator()(int i, int j) {
    int k = lcp(i, j);
    return i + k >= n ? true : j + k >= n ? false : s[i + k] <= s[j + k];
  }

  static ull hash(const string &t) {
    ull h = 0;
    REP(i, SZ(t)) h = t[i] + h * p;
    return h;
  }

  inline ull hash(int b, int e) { return phash[e] - phash[b] * pow[e - b]; }

  inline int find(string t) {
    int w = t.size(), count = 0;
    if (w > SZ(s))
      return 0;
    ull h = hash(t);
    REP(i, n - w + 1) count += (hash(i, i + w) == h);
    return count;
  }

  inline int lcp(int i, int j) {
    int l = 0, r = min(n - i, n - j) + 1;
    while (r - l > 1) {
      int m = (l + r) / 2;
      (hash(i, i + m) == hash(j, j + m) ? l : r) = m;
    }
    return l;
  }
};

// O(n (log n)^2)
vector<int> suffixArray(const RollingHash &rh) {
  vector<int> sa(rh.n + 1);
  REP(i, rh.n + 1) sa[i] = i;
  sort(ALL(sa), rh);
  return sa;
}

bool contain(const string &S, const vector<int> &sa, const string &T) {
  int a = 0, b = S.length();
  while (b - a > 1) {
    int c = (a + b) / 2;
    if (S.compare(sa[c], T.length(), T) < 0)
      a = c;
    else
      b = c;
  }
  return S.compare(sa[b], T.length(), T) == 0;
}

int main(void) {
  ios::sync_with_stdio(false);

  int n;
  string s, t;
  cin >> s;
  RollingHash rh = RollingHash(s);
  vector<int> sa = suffixArray(rh);

  cin >> n;
  while (n--) {
    cin >> t;
    cout << !!rh.find(t) << endl;
  }

  return 0;
}