题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6704
Problem Description
You are given a string S consisting of only lowercase english letters and some queries.
For each query (l,r,k), please output the starting position of the k-th occurence of the substring S l , S l + 1 , . . . S r ∈ S S_l, S_{l+1},...S_{r} \in S Sl,Sl+1,...Sr∈S.
Input
The first line contains an integer T ( 1 ≤ T ≤ 20 ) T(1\leq T\leq20) T(1≤T≤20), denoting the number of test cases.
The first line of each test case contains two integer N ( 1 ≤ N ≤ 1 0 5 ) , Q ( 1 ≤ Q ≤ 1 0 5 ) N(1\leq N\leq 10^5),Q(1\leq Q\leq 10^5) N(1≤N≤105),Q(1≤Q≤105), denoting the length of S and the number of queries.
The second line of each test case contains a string S ( ∣ S ∣ = N ) S(|S|=N) S(∣S∣=N) consisting of only lowercase english letters.
Then Q lines follow, each line contains three integer l , r ( 1 ≤ l ≤ r ≤ N ) l,r(1\leq l\leq r\leq N) l,r(1≤l≤r≤N) and k ( 1 ≤ k ≤ N ) k(1\leq k\leq N) k(1≤k≤N), denoting a query.
There are at most 5 testcases which N is greater than 1 0 3 10^3 103.
Output
For each query, output the starting position of the k-th occurence of the given substring.
If such position don’t exists, output −1 instead.
题意
共有T组数据
对于每一组数据有长度为N的字符串S,且对字符串S将进行Q次查询
查询内容为子串S[l,r]在S中出现第k次的子串首字母位置,若不存在则输出-1
题解
后缀数组+ST+主席树
后缀数组预处理字符串S,在对height打ST表,二分查找得到区间后跑主席树第K小
#include
#include
#include
using namespace std;
const int maxn = 1e5+10;
struct node{
int lchild, rchild, val;
}tree[maxn*50];
struct SuffixArray{
char s[maxn];
int w[maxn];
int n;
int fir[maxn], sec[maxn];
int sa[maxn], rk[maxn];
int height[maxn], h[maxn];
int buf[maxn], tmp[maxn];
int st[maxn][20];
void read(){
memset(h, 0, sizeof(h));
scanf("%s", s+1);
n = strlen(s+1);
for(int i = 1; i <= n; i++) w[i] = s[i]-'a'+1;
}
void build(){
memset(buf, 0, sizeof(buf));
for(int i = 1; i <= n; i++) buf[w[i]]++;
for(int i = 1; i <= 26; i++) buf[i] += buf[i-1];
for(int i = 1; i <= n; i++) rk[i] = buf[w[i]-1]+1;
for(int i = 1; i <= n; i <<= 1){
for(int j = 1; j <= n; j++){
fir[j] = rk[j];
sec[j] = j+i > n? 0 : rk[j+i];
}
memset(buf, 0, sizeof(buf));
for(int j = 1; j <= n; j++) buf[sec[j]]++;
for(int j = 1; j <= n; j++) buf[j] += buf[j-1];
for(int j = 1; j <= n; j++) tmp[n - (--buf[sec[j]])] = j;
memset(buf, 0, sizeof(buf));
for(int j = 1; j <= n; j++) buf[fir[j]]++;
for(int j = 1; j <= n; j++) buf[j] += buf[j-1];
for(int j = 1; j <= n; j++) sa[buf[fir[tmp[j]]]--] = tmp[j];
bool unique = true;
for(int j = 1, last = 0; j <= n; j++){
int k = sa[j];
if(!last) rk[k] = 1;
else if(fir[last] == fir[k] && sec[last] == sec[k]) rk[k] = rk[last], unique = false;
else rk[k] = rk[last]+1;
last = k;
}
if(unique) break;
}
}
void getHight(){
for(int i = 1; i <= n; i++){
if(rk[i] == 1) continue;
int x = sa[rk[i]-1], y = i, k = max(h[i-1]-1, 0);
while(x+k <= n && y+k <= n && s[x+k]==s[y+k])k++;
h[i] = k;
}
for(int i = 1; i <= n; i++){
height[i] = h[sa[i]];
}
}
void getST(){
for(int i = 1; i <= n+1; i++) st[i][0] = height[i];
for(int i = 1; i <= 17; i++){
for(int j = 1; j + (1 << i) - 1 <= n+1; j++){
st[j][i] = min(st[j][i-1], st[j+(1<<(i-1))][i-1]);
}
}
}
int getL(int l, int r, int k){
while(l <= r){
int mid = (l+r)>>1;
int m = 0;
while((1 << (m+1)) <= r-mid) m++;
int sum = min(st[mid+1][m], st[r-(1 << m)+1][m]);
if(sum >= k) r = mid;
else l = mid+1;
}
return r;
}
int getR(int l, int r, int k){
while(l < r){
int mid = (l+r)>>1;
int m = 0;
while((1 << (m+1)) <= mid-l+1) m++;
int sum = min(st[l][m], st[mid-(1 << m)+1][m]);
if(sum >= k) l = mid+1;
else r = mid;
}
return l;
}
}SA;
int head[maxn], cnt;
void init(){
memset(head, 0, sizeof(head));
for(int i = 0; i <= cnt; i++) tree[i].lchild = tree[i].rchild = tree[i].val = 0;
cnt = 0;
}
void update(int u, int l, int r, int x){
int root_x = head[u-1], root_y = ++cnt;
head[u] = root_y;
while(l != r){
int mid = (l+r)>>1;
tree[root_y].val = tree[root_x].val+1;
if(x <= mid){
tree[root_y].lchild = ++cnt;
tree[root_y].rchild = tree[root_x].rchild;
root_x = tree[root_x].lchild;
root_y = tree[root_y].lchild;
r = mid;
}
else{
tree[root_y].lchild = tree[root_x].lchild;
tree[root_y].rchild = ++cnt;
root_x = tree[root_x].rchild;
root_y = tree[root_y].rchild;
l = mid+1;
}
}
tree[root_y].val = tree[root_x].val+1;
}
int query(int root_x, int root_y, int l, int r, int k){
while(l!=r){
int mid = (l+r)>>1;
int sum = tree[tree[root_y].lchild].val - tree[tree[root_x].lchild].val;
if(sum >= k){
root_x = tree[root_x].lchild;
root_y = tree[root_y].lchild;
r = mid;
}
else{
k -= sum;
root_x = tree[root_x].rchild;
root_y = tree[root_y].rchild;
l = mid+1;
}
}
return l ;
}
int main(){
int T;
scanf("%d", &T);
while(T--){
int n, m;
scanf("%d%d", &n, &m);
SA.read();
SA.build();
SA.getHight();
SA.getST();
init();
for(int i = 1; i <= n; i++){
update(i, 1, n, SA.sa[i]);
}
for(int i = 0; i < m; i++){
int l, r, k;
scanf("%d%d%d", &l, &r, &k);
int len = r-l+1;
int x = SA.getL(1, SA.rk[l], len);
int y = SA.getR(SA.rk[l]+1, n+1, len);
if(y-x<k) printf("-1\n");
else printf("%d\n", query(head[x-1], head[y-1], 1, n, k));
}
}
return 0;
}