字符串游戏 - 主席树 - 后缀数组

题目大意:给你个字符串,若干次询问本质不同的子串中第k1小中第k2次出现的子串,或者S[l,r]这个子串在S中的排名(本质不同的排名)以及在相同的子串中是地几个出现的。
题解:后缀数组后第一问可以预处理倍增定位然后主席树;第二问可以直接线段树。

#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<assert.h>
#define N 500010
#define LOG 21
#define lint long long
#define gc getchar()
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define debug(x) cerr<<#x<<"="<<x
#define sp <<" "
#define ln <<endl
using namespace std;
inline int inn()
{
    int x,ch;while((ch=gc)<'0'||ch>'9');
    x=ch^'0';while((ch=gc)>='0'&&ch<='9')
        x=(x<<1)+(x<<3)+(ch^'0');return x;
}
inline lint inln()
{
    lint x,ch;while((ch=gc)<'0'||ch>'9');
    x=ch^'0';while((ch=gc)>='0'&&ch<='9')
        x=(x<<1)+(x<<3)+(ch^'0');return x;
}
int wa[N<<1],wb[N<<1],cnt[N],v[N],sa[N],rk[N],h[N],a[N];
char s[N];lint ps[N];int mnv[N][LOG],Log[N];
inline int cmp(int *a,int x,int y,int l) { return a[x]==a[y]&&a[x+l]==a[y+l]; }
int getSA(int *a,int n,int m)
{
    int *x=wa,*y=wb,i,j,p;
    memset(wa,0,sizeof(wa));
    memset(wb,0,sizeof(wb));
    for(i=1;i<=m;i++) cnt[i]=0;
    for(i=1;i<=n;i++) cnt[x[i]=a[i]]++;
    for(i=1;i<=m;i++) cnt[i]+=cnt[i-1];
    for(i=n;i;i--) sa[cnt[x[i]]--]=i;
    for(p=0,j=1;p<=n;j<<=1,m=p)
    {
        for(p=0,i=n-j+1;i<=n;i++) y[++p]=i;
        for(i=1;i<=n;i++)
            if(sa[i]>j) y[++p]=sa[i]-j;
        for(i=1;i<=m;i++) cnt[i]=0;
        for(i=1;i<=n;i++) cnt[v[i]=x[y[i]]]++;
        for(i=1;i<=m;i++) cnt[i]+=cnt[i-1];
        for(i=n;i;i--) sa[cnt[v[i]]--]=y[i];
        for(swap(x,y),p=i=1;i<=n;i++)
            x[sa[i]]=(cmp(y,sa[i],sa[i-1],j)?p-1:(p++));
    }
    for(i=1;i<=n;i++) rk[sa[i]]=i;
    for(i=1,p=0;i<=n;h[rk[i++]]=p)
        for((p?p--:0),j=sa[rk[i]-1];a[i+p]==a[j+p];p++);
    return 0;
}
inline int LCP(int x,int y)
{
    assert(x!=y);if(x>y) swap(x,y);x++;int k=Log[y-x+1];
    return min(mnv[x][k],mnv[y-(1<<k)+1][k]);
}
inline int get_s(int x,int len)
{
    int L=1,R=x-1,mid=(L+R)>>1;
    while(L<=R)
    {
        if(LCP(mid,x)>=len) R=mid-1;
        else L=mid+1;mid=(L+R)>>1;
    }
    return L;
}
inline int get_t(int x,int len,int n)
{
    int L=x+1,R=n,mid=(L+R)>>1;
    while(L<=R)
    {
        if(LCP(x,mid)>=len) L=mid+1;
        else R=mid-1;mid=(L+R)>>1;
    }
    return R;
}
struct segment{ int s;segment *ch[2]; }*T[N];
inline int push_up(segment* &rt) { return rt->s=rt->ch[0]->s+rt->ch[1]->s; }
int build(segment* &rt,int l,int r)
{
    rt=new segment,rt->s=0;if(l==r) return 0;int mid=(l+r)>>1;
    return build(rt->ch[0],l,mid),build(rt->ch[1],mid+1,r),0;
}
int build(segment* &now,segment* &pre,int p,int l,int r)
{
    int mid=(l+r)>>1;now=new segment,now->s=0;
    now->ch[0]=pre->ch[0],now->ch[1]=pre->ch[1];
    if(l==r) return now->s=1;
    if(p<=mid) build(now->ch[0],pre->ch[0],p,l,mid);
    else build(now->ch[1],pre->ch[1],p,mid+1,r);
    return push_up(now);
}
int kth(segment* &x,segment* &y,int k,int l,int r)
{
    if(l==r) return l;int mid=(l+r)>>1;
    if(y->ch[0]->s-x->ch[0]->s>=k) return kth(x->ch[0],y->ch[0],k,l,mid);
    k-=y->ch[0]->s-x->ch[0]->s;return kth(x->ch[1],y->ch[1],k,mid+1,r);
}
int query(segment* &x,segment* &y,int s,int t,int l,int r)
{
    int mid=(l+r)>>1,ans=0;if(s<=l&&r<=t) return y->s-x->s;
    if(s<=mid) ans+=query(x->ch[0],y->ch[0],s,t,l,mid);
    if(mid<t) ans+=query(x->ch[1],y->ch[1],s,t,mid+1,r);
    return ans;
}
int main()
{
    scanf("%s",s+1);int q=inn(),n=strlen(s+1);
    for(int i=1;i<=n;i++) a[i]=s[i]-'a'+1;getSA(a,n,30);
    for(int i=1;i<=n;i++) ps[i]=n-sa[i]+1-h[i]+ps[i-1];
//  for(int i=1;i<=n;i++) debug(i)sp,debug(sa[i])sp,debug(h[i])sp,debug(ps[i])ln;
    for(int i=2;i<=n;i++) mnv[i][0]=h[i],Log[i]=Log[i>>1]+1;
    for(int j=1;(1<<j)<=n;j++) for(int i=2;i+(1<<j)-1<=n;i++)
        mnv[i][j]=min(mnv[i][j-1],mnv[i+(1<<(j-1))][j-1]);
    build(T[0],1,n);for(int i=1;i<=n;i++) build(T[i],T[i-1],sa[i],1,n);
    while(q--)
        if(inn()==1)
        {
            lint k1=inln();int k2=inn();
            int L=1,R=n,mid=(L+R)>>1;
            while(L<=R)
            {
                if(ps[mid]<k1) L=mid+1;
                else R=mid-1;mid=(L+R)>>1;
            }
            int len=h[L]+(int)(k1-ps[R]),
                s=L,t=get_t(s,len,n),l=kth(T[s-1],T[t],k2,1,n);
            printf("%d %d\n",l,l+len-1);
        }
        else{
            int l=inn(),r=inn(),x=rk[l],len=r-l+1;
            int s=get_s(x,len),t=get_t(x,len,n);
            printf("%lld %d\n",ps[s-1]+len-h[s],query(T[s-1],T[t],1,l,1,n));
        }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/Mys_C_K/article/details/82352481