Codeforces 666E E - Forensic Examination SA + 莫队 + 线段树
我也不知道为什么这个复杂度能过, 而且跑得还挺快, 数据比较水?
在sa上二分出上下界, 然后莫队 + 线段树维护区间众数。
#include<bits/stdc++.h> #define LL long long #define fi first #define se second #define mk make_pair #define PLL pair<LL, LL> #define PLI pair<LL, int> #define PII pair<int, int> #define SZ(x) ((int)x.size()) #define ull unsigned long long using namespace std; const int N = 6e5 + 7; const int inf = 0x3f3f3f3f; const LL INF = 0x3f3f3f3f3f3f3f3f; const int mod = 1e9 + 7; const double eps = 1e-9; const double PI = acos(-1); #define F(x) ((x) / 3 + ((x) % 3 == 1 ? 0 : tb)) #define G(x) ((x) < tb ? (x) * 3 + 1 : ((x) - tb) * 3 + 2) int r[3 * N], sa[3 * N]; int wa[3 * N], wb[3 * N], wv[3 * N], ss[3 * N]; int rnk[N], lcp[N]; int c0(int *r, int a, int b) {return r[a] == r[b] && r[a + 1] == r[b + 1] && r[a + 2] == r[b + 2]; } int c12(int k, int *r, int a, int b) { if(k == 2) return r[a] < r[b] || r[a] == r[b] && c12(1, r, a + 1, b + 1); return r[a] < r[b] || r[a] == r[b] && wv[a + 1] < wv[b + 1]; } void sort(int *r, int *a, int *b, int n, int m) { for(int i = 0; i < n; i++) wv[i] = r[a[i]]; for(int i = 0; i < m; i++) ss[i] = 0; for(int i = 0; i < n; i++) ss[wv[i]]++; for(int i = 1; i < m; i++) ss[i] += ss[i - 1]; for(int i = n - 1; i >= 0; i--) b[--ss[wv[i]]] = a[i]; } void DC3(int *r, int *sa, int n, int m) { int i, j, p; int *san = sa + n, *rn = r + n; int ta = 0, tb = (n + 1) / 3, tbc = 0; r[n] = r[n + 1] = 0; for(i = 0; i < n; i++) if(i % 3 != 0) wa[tbc++] = i; sort(r + 2, wa, wb, tbc, m); sort(r + 1, wb, wa, tbc, m); sort(r, wa, wb, tbc, m); for(p = 1, rn[F(wb[0])] = 0, i = 1; i < tbc; i++) rn[F(wb[i])] = c0(r, wb[i - 1], wb[i]) ? p - 1 : p++; if(p < tbc) DC3(rn, san, tbc, p); else for(i = 0; i < tbc; i++) san[rn[i]] = i; for(i = 0; i < tbc; i++) if(san[i] < tb) wb[ta++] = san[i] * 3; if(n % 3 == 1) wb[ta++] = n - 1; sort(r, wb, wa, ta, m); for(i = 0; i < tbc; i++) wv[wb[i] = G(san[i])] = i; for(i = 0, j = 0, p = 0; i < ta && j < tbc; p++) sa[p] = c12(wb[j] % 3, r, wa[i], wb[j]) ? wa[i++] : wb[j++]; for( ; i < ta; p++) sa[p] = wa[i++]; for( ; j < tbc; p++) sa[p] = wb[j++]; } void calc_LCP(int *r, int *sa, int n) { int k = 0; for(int i = 0; i < n; i++) rnk[sa[i]] = i; for(int i = 0; i < n - 1; lcp[rnk[i++]] = k) { if(k) k--; for(int j = sa[rnk[i] - 1]; r[i + k] == r[j + k]; k++); } } int Log[N]; struct ST { int dp[N][20], ty; void build(int n, int b[], int _ty) { ty = _ty; for(int i = -(Log[0]=-1); i < N; i++) Log[i] = Log[i - 1] + ((i & (i - 1)) == 0); for(int i = 1; i <= n; i++) dp[i][0] = ty * b[i]; for(int j = 1; j <= Log[n]; j++) for(int i = 1; i+(1<<j)-1 <= n; i++) dp[i][j] = max(dp[i][j-1], dp[i+(1<<(j-1))][j-1]); } inline int query(int x, int y) { int k = Log[y - x + 1]; return ty * max(dp[x][k], dp[y-(1<<k)+1][k]); } }; namespace SGT { #define lson l, mid, rt << 1 #define rson mid + 1, r, rt << 1 | 1 const int N = 5e4 + 7; PII a[N << 2]; int b[N]; void build(int l, int r, int rt) { if(l == r) { a[rt].se = -l; b[l] = rt; return; } int mid = (l + r) >> 1; build(lson); build(rson); a[rt] = max(a[rt << 1], a[rt << 1 | 1]); } inline void update(int x, int val) { x = b[x]; a[x].fi += val; x >>= 1; for( ; x; x >>= 1) a[x] = max(a[x << 1], a[x << 1 | 1]); } PII query(int L, int R, int l, int r, int rt) { if(R < l || r < L) return mk(-inf, inf); if(L <= l && r <= R) return a[rt]; int mid = (l + r) >> 1; return max(query(L, R, lson), query(L, R, rson)); } } struct Qus { int L, R, numl, numr, id; bool operator < (const Qus& rhs) const { if(L / 750 == rhs.L / 750) return R < rhs.R; return L < rhs.L; } }; int n, m, q, mxc = 256, who[N]; PII ans[N]; char s[N]; ST rmq; Qus qus[N]; int main() { scanf("%s", s); for(int i = 0; s[i]; i++) r[n++] = s[i], mxc = max(mxc, (int)s[i]); scanf("%d", &m); for(int i = 1; i <= m; i++) { r[n++] = mxc++; scanf("%s", s); for(int j = 0; s[j]; j++) r[n] = s[j], who[n++] = i; } r[n] = 0; DC3(r, sa, n + 1, mxc); calc_LCP(r, sa, n + 1); rmq.build(n, lcp, -1); scanf("%d", &q); for(int i = 1; i <= q; i++) { int l, r, pl, pr; scanf("%d%d%d%d", &l, &r, &pl, &pr); int pos = rnk[pl - 1], len = pr - pl + 1; int low = 1, high = pos - 1, L = pos, R = pos; while(low <= high) { int mid = (low + high) >> 1; if(rmq.query(mid + 1, pos) >= len) L = mid, high = mid - 1; else low = mid + 1; } low = pos + 1, high = n; while(low <= high) { int mid = (low + high) >> 1; if(rmq.query(pos + 1, mid) >= len) R = mid, low = mid + 1; else high = mid - 1; } qus[i] = Qus{L, R, l, r, i}; } SGT::build(1, m, 1); sort(qus + 1, qus + 1 + q); int l = 1, r = 0; for(int i = 1; i <= q; i++) { int L = qus[i].L, R = qus[i].R, numl = qus[i].numl, numr = qus[i].numr; while(r < R) r++, SGT::update(who[sa[r]], 1); while(l > L) l--, SGT::update(who[sa[l]], 1); while(r > R) SGT::update(who[sa[r]], -1), r--; while(l < L) SGT::update(who[sa[l]], -1), l++; ans[qus[i].id] = SGT::query(numl, numr, 1, m, 1); } for(int i = 1; i <= q; i++) printf("%d %d\n", -ans[i].se, ans[i].fi); return 0; } /* */