hdu6704 K-th occurrence

鏈接

點擊跳轉

題解

後綴數組上二分確定區間,然後查詢主席樹區間第kk

代碼

#include <bits/stdc++.h>
#define linf (1ll<<60)
#define iinf 0x3f3f3f3f
#define cl(x) memset(x,0,sizeof(x))
#define rep(_,__) for(_=1;_<=(__);_++)
using namespace std;
#define maxn 100010
#define maxk 17
typedef long long ll;
typedef pair<ll,ll> pll;
struct SuffixArray
{
    int sa[maxn], rank[maxn], ws[maxn], wv[maxn], wa[maxn], wb[maxn], height[maxn], st[maxk+2][maxn], N;
    bool cmp(int *r, int a, int b, int l){return r[a]==r[b] and r[a+l]==r[b+l];}
    void clear()
    {
        cl(sa), cl(rank), cl(ws), cl(wv), cl(wa), cl(wb), cl(height);
    }
    void build(int *r, int n, int m)
    {
        N=n;
        n++;
        int i, j, k=0, p, *x=wa, *y=wb, *t;
        for(i=0;i<m;i++)ws[i]=0;
        for(i=0;i<n;i++)ws[x[i]=r[i]]++;
        for(i=1;i<m;i++)ws[i]+=ws[i-1];
        for(i=n-1;i>=0;i--)sa[--ws[x[i]]]=i;
        for(p=j=1;p<n;j<<=1,m=p)
        {
            for(p=0,i=n-j;i<n;i++)y[p++]=i;
            for(i=0;i<n;i++)if(sa[i]>=j)y[p++]=sa[i]-j;
            for(i=0;i<n;i++)wv[i]=x[y[i]];
            for(i=0;i<m;i++)ws[i]=0;
            for(i=0;i<n;i++)ws[wv[i]]++;
            for(i=1;i<m;i++)ws[i]+=ws[i-1];
            for(i=n-1;i>=0;i--)sa[--ws[wv[i]]]=y[i];
            for(t=x,x=y,y=t,p=1,i=1,x[sa[0]]=0;i<n;i++)
                x[sa[i]]=cmp(y,sa[i-1],sa[i],j)?p-1:p++;
        }
        
        for(i=0;i<n;i++)rank[sa[i]]=i;
        
        for(i=0;i<n-1;height[rank[i++]]=k)
            for(k?k--:0,j=sa[rank[i]-1];r[i+k]==r[j+k];k++);
    }
    void build_st()     //st表
    {
        int i, k;
        for(i=1;i<=N;i++)st[0][i]=height[i];
        for(k=1;k<=maxk;k++)
            for(i=1;i+(1<<k)-1<=N;i++)
                st[k][i]=min(st[k-1][i],st[k-1][i+(1<<k-1)]);
    }
    int lcp(int x, int y)   //最長公共前綴
    {
        int l=rank[x], r=rank[y];
        if(l>r)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<<t)+1]);
    }
}SA;
int ndtot, N;
struct segtree{int l, r, size;segtree *ch[2];}pool[maxn*30], *root[maxn];
void ins(segtree *pre, segtree *now, int pos)
{
    int mid=(pre->l+pre->r)>>1;
    *now=*pre;now->size++;
    if(pre->l==pre->r)return;
    if(pos<=mid)ins(pre->ch[0],now->ch[0]=pool+ ++ndtot,pos);
    if(pos>mid)ins(pre->ch[1],now->ch[1]=pool+ ++ndtot,pos);
}
int find(segtree *pre, segtree *now, int k)
{
    int sz;
    if(pre->l==pre->r)return pre->l;
    sz=now->ch[0]->size-pre->ch[0]->size;
    if(k<=sz)return find(pre->ch[0],now->ch[0],k);
    return find(pre->ch[1],now->ch[1],k-sz);
}
void build(segtree *p, int l, int r)
{
    int mid=(l+r)>>1;
    p->l=l, p->r=r, p->size=0;
    if(l==r)return;
    build(p->ch[0]=pool+ ++ndtot,l,mid);
    build(p->ch[1]=pool+ ++ndtot,mid+1,r);
}
int r[maxn];
char s[maxn];
pair<int,int> get_interval(int p, int len)
{
    int l, r, mid;
    pair<int,int> pr;
    
    l=1, r=SA.rank[p];
    while(l<r)
    {
        mid=l+r>>1;
        if(SA.lcp(p,SA.sa[mid])>=len)r=mid;
        else l=mid+1;
    }
    pr.first = l;
    
    l=SA.rank[p], r=N;
    while(l<r)
    {
        mid=l+r+1>>1;
        if(SA.lcp(p,SA.sa[mid])>=len)l=mid;
        else r=mid-1;
    }
    pr.second=l;
    return pr;
}
int main()
{
    int T, a, b, i, Q, L, k;
    cin>>T;
    while(T--)
    {
        scanf("%d%d",&N,&Q);
        scanf("%s",s);
        for(i=0;i<N;i++)r[i]=s[i];
        r[N]=0;
        SA.build(r,N,300);
        SA.build_st();
        ndtot=0;
        build(root[0]=pool+ ++ndtot,1,N);
        for(i=1;i<=N;i++)ins(root[i-1],root[i]=pool+ ++ndtot,SA.sa[i]+1);
        while(Q--)
        {
            scanf("%d%d%d",&a,&b,&k);
            auto I = get_interval(a-1,b-a+1);
            if(I.second-I.first+1 < k)
            {
                printf("-1\n");
            }
            else printf("%d\n",find(root[I.first-1],root[I.second],k));
        }
    }
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章