K-th occurrence HDU - 6704 (主席树+后缀数组+二分)

题目传送

题意:给出一个字符串,找出某个子串第k次出现的位置

思路:后缀数组sa[i]数组表示排名第i的后缀第一次出现的下标,求第k次出现的下标只需要在某个区间中求sa数组中的第k大即可(主席树求第k大),确定区间时利用后缀数组中的lcp确定与子串具有相同前缀的后缀第一次出现位置和最后一次出现位置(枚举超时,二分实现)。

代码:

#include 
#include 
#include 
#include 
#include
#include
using namespace std;
const int MAXN=1e5+1000;
int n;
//后缀数组部分 
struct SA{
	int sa[MAXN];
	int t1[MAXN],t2[MAXN],c[MAXN];
	int rank1[MAXN],height[MAXN];
	int st[20][MAXN];
	void build_sa(int s[],int n,int m)
	{
	    int i,j,p,*x=t1,*y=t2;
	    for(i=0;i=0;i--)sa[--c[x[i]]]=i;
	    for(j=1;j<=n;j<<=1)
	    {
	        p=0;
	        for(i=n-j;i=j)y[p++]=sa[i]-j;
	        for(i=0;i=0;i--)sa[--c[x[y[i]]]]=y[i];
	        swap(x,y);
	        p=1;x[sa[0]]=0;
	        for(i=1;i=n)break;
	        m=p;
	    }
	}
	void getHeight(int s[],int n)
	{
	    int i,j,k=0;
	    for(i=0;i<=n;i++)rank1[sa[i]]=i;
	    for(i=0;ir)swap(l,r);
	    if(l==r)return n-sa[l];
	    int t=log2(r-l);
	    return min(st[t][l+1],st[t][r-(1<>1;
	if(pos<=m) update(l,m,tree[x].l,tree[y].l,pos);
	else update(m+1,r,tree[x].r,tree[y].r,pos);
}
int query(int l,int r,int x,int y,int k){
	if(l==r) return l;
	int m=(l+r)>>1;
	int tmp=tree[tree[y].l].num-tree[tree[x].l].num;
	if(tmp>1;
		if(sa.lcp(p,sa.sa[m])>=len){//大于子串长度此后缀中包含子串
			ans=m;
			r=m-1;
		}
		else l=m+1;
	}
	return ans;
 } 
 int getr(int l,int r,int len,int p)
{
	int ans;
	while(l<=r){
		int m=(l+r)>>1;
		if(sa.lcp(p,sa.sa[m])>=len){
			ans=m;
			l=m+1;
		}
		else r=m-1;
	}
	return ans;
} 
int main()
{
	int kase;
	scanf("%d",&kase);
	while(kase--)
	{
		int q;
		tot=0;
		scanf("%d%d",&n,&q);
		scanf("%s",p);
		for(int i=0;i

 

你可能感兴趣的:(算法,主席树,后缀数组)