题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6704
题意为查询子串s[l...r]第k次出现的位置。
写完博客后5分钟的更新
写完博客才发现这份代码和杭电的代码查重了....
为什么会变成这样呢?是我先交的,明明是我先交的…
激动!!第一次网络赛做出这种(板子)题。
首先求一下后缀数组的Height,我们知道Height数组表示两个排名相邻的后缀的最长公共前缀,则Height数组的区间最小值即为区间排名相邻的后缀的最长公共前缀。
我们想知道那些后缀包含了所查询的区间s[l...r]这样的前缀,则先找到s[l...n]这个后缀的排名,然后在包含这个排名的Height数组中找到最长的区间,且该区间最小值要大于等于r-l+1。即该区间内的后缀的最长公共前缀包含s[l...r]。
找这个最长的区间就可以分别二分左右端点,判断用ST表预处理Height数组,然后O(1)查询即可。
然后我们的任务就是在这个区间内找到第k小的位置。这个问题就可以对后缀数组的排名建主席树。然后查询即可。
#include<bits/stdc++.h> #define lson l,mid,i<<1 #define rson mid+1,r,i<<1|1 using namespace std; typedef long long ll; typedef unsigned long long ull; const int maxn = 2e5 + 110; int sa[maxn], tax[maxn], rak[maxn], tp[maxn], Height[maxn], lg[maxn]; int dp[maxn][20]; int root[maxn], ls[maxn * 40], rs[maxn * 40], val[maxn * 40], cnt; char s[maxn]; void Qsort(int n, int m) { for (int i = 0; i < m; i++) tax[i] = 0; for (int i = 0; i < n; i++) tax[rak[i]]++; for (int i = 0; i < m; i++) tax[i] += tax[i - 1]; for (int i = n - 1; i >= 0; i--) sa[--tax[rak[tp[i]]]] = tp[i]; } void suffix(int n, int m) {//n为原串长度+1,m为原串的种类 for (int i = 0; i < n; i++) rak[i] = s[i], tp[i] = i; Qsort(n, m); //debug(); for (int k = 1; k <= n; k <<= 1) { int p = 0; for (int i = n - k; i < n; i++) tp[p++] = i; for (int i = 0; i < n; i++) if (sa[i] >= k) tp[p++] = sa[i] - k; Qsort(n, m); swap(rak, tp); p = 1; rak[sa[0]] = 0; for (int i = 1; i < n; i++) rak[sa[i]] = (tp[sa[i - 1]] == tp[sa[i]] && tp[sa[i - 1] + k] == tp[sa[i] + k]) ? p - 1 : p++; if (p >= n) break; m = p; } } void getH(int n) { int j, k = 0; for (int i = 0; i <= n; i++) rak[sa[i]] = i; for (int i = 0; i < n; i++) { if (k)k--; j = sa[rak[i] - 1]; while (s[i + k] == s[j + k]) k++; Height[rak[i]] = k; } } void RMQ(int n) { for (int i = 1; i <= n; i++) dp[i][0] = Height[i]; for (int j = 1; (1 << j) <= n; j++) { for (int i = 1; i + (1 << j) - 1 <= n; i++) dp[i][j] = min(dp[i][j - 1], dp[i + (1 << (j - 1))][j - 1]); } lg[0] = -1; for (int i = 1; i <= n; i++) { if ((i&(i - 1)) == 0) lg[i] = lg[i - 1] + 1; else lg[i] = lg[i - 1]; } } int queryR(int l, int r) { int k = lg[r - l + 1]; return min(dp[l][k], dp[r - (1 << k) + 1][k]); } void build(int l, int r, int &i) { i = ++cnt; val[i] = 0; if (l == r) return; int mid = l + r >> 1; build(l, mid, ls[i]); build(mid + 1, r, rs[i]); } void update(int k, int l, int r, int &i) { ls[++cnt] = ls[i], rs[cnt] = rs[i], val[cnt] = val[i] + 1; i = cnt; if (l == r) return; int mid = l + r >> 1; if (k <= mid) update(k, l, mid, ls[i]); else update(k, mid + 1, r, rs[i]); } int query(int u, int v, int k, int l, int r) { if (l == r) return l; int x = val[ls[v]] - val[ls[u]]; int mid = l + r >> 1; if (x >= k) return query(ls[u], ls[v], k, l, mid); else return query(rs[u], rs[v], k - x, mid + 1, r); } int main() { int t; scanf("%d", &t); while (t--) { int n, q, cnt = 0; scanf("%d%d", &n, &q); scanf("%s", s); suffix(n + 1, 256); getH(n); for (int i = 1; i <= n; i++) ++sa[i]; for (int i = n; i >= 1; i--) rak[i] = rak[i - 1]; RMQ(n); build(1, n, root[0]); for (int i = 1; i <= n; i++) { root[i] = root[i - 1]; update(sa[i], 1, n, root[i]); } //for (int i = 1; i <= n; i++) // printf("%d%c", sa[i], i == n ? ' ' : ' '); //for (int i = 1; i <= n; i++) // printf("%d%c", rak[i], i == n ? ' ' : ' '); //for (int i = 1; i <= n; i++) // printf("%d%c", Height[i], i == n ? ' ' : ' '); while (q--) { int l, r, k, len; scanf("%d%d%d", &l, &r, &k); len = r - l + 1; int x = rak[l], y = rak[l]; int L = x + 1, R = n; while (L <= R) { int mid = L + R >> 1; if (queryR(L, mid) >= len) y = mid, L = mid + 1; else R = mid - 1; } L = 2, R = x; while (L <= R) { int mid = L + R >> 1; if (queryR(mid, R) >= len) x = mid - 1, R = mid - 1; else L = mid + 1; } //cout << x << " " << y << endl; if (y - x + 1 < k) printf("-1 "); else printf("%d ", query(root[x - 1], root[y], k, 1, n)); } } }