HDU6704 K-th occurrence(CCPC網絡賽T3)

題目鏈接: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 Sl,Sl+1,...SrSS_l, S_{l+1},...S_{r} \in S.

Input
The first line contains an integer T(1T20)T(1\leq T\leq20), denoting the number of test cases.

The first line of each test case contains two integer N(1N105),Q(1Q105)N(1\leq N\leq 10^5),Q(1\leq Q\leq 10^5), 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) consisting of only lowercase english letters.

Then Q lines follow, each line contains three integer l,r(1lrN)l,r(1\leq l\leq r\leq N) and k(1kN)k(1\leq k\leq N), denoting a query.

There are at most 5 testcases which N is greater than 10310^3.

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;
} 
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章