題目鏈接:http://acm.hdu.edu.cn/showproblem.php?pid=6704
K-th occurrence
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 .
Input
The first line contains an integer , denoting the number of test cases.
The first line of each test case contains two integer , denoting the length of S and the number of queries.
The second line of each test case contains a string consisting of only lowercase english letters.
Then Q lines follow, each line contains three integer and , denoting a query.
There are at most 5 testcases which N is greater than .
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<iostream>
#include<cstdio>
#include<cstring>
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;
}