hdu6704(sam+主席樹)

題目鏈接:http://acm.hdu.edu.cn/showproblem.php?pid=6704

思路:對於每個包含前綴的endpos求出它所代表的子串第一次出現的位置,對於每次詢問,找到子串對應的endpos所在位置,

然後就相當於查詢當前節點子樹第k大的值是什麼,dfs序然後主席樹就行了

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <bitset>
#include <cmath>
#include <cctype>
#include <unordered_map>
#include <iostream>
#include <algorithm>
#include <string>
#include <vector>
#include <queue>
#include <map>
#include <set>
#include <sstream>
#include <iomanip>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const ll inff = 0x3f3f3f3f3f3f3f3f;
#define FOR(i,a,b) for(int i(a);i<=(b);++i)
#define FOL(i,a,b) for(int i(a);i>=(b);--i)
#define REW(a,b) memset(a,b,sizeof(a))
#define inf int(0x3f3f3f3f)
#define si(a) scanf("%d",&a)
#define sl(a) scanf("%lld",&a)
#define sd(a) scanf("%lf",&a)
#define ss(a) scanf("%s",a)
#define mod ll(998244353)
#define pb push_back
#define eps 1e-7
#define lc d<<1
#define rc d<<1|1
#define Pll pair<ll,ll>
#define P pair<int,int>
#define pi acos(-1)
const int MAXN=1e5+8;
char a[MAXN];
struct as{
int l,r,sum;}tr[MAXN*40];
int rt[MAXN<<1],qw,n,q,l,r,k,sa,head[MAXN<<1];
struct node{
int next,to;}e[MAXN<<2];
void add2(int a,int b)
{
    e[sa].next=head[a];
    e[sa].to=b;
    head[a]=sa++;
}
void add1(int l,int r,int &x,int y,int pos)
{
    tr[++qw]=tr[y],tr[qw].sum++,x=qw;
    if(l==r)  return;
    int mid=(l+r)>>1;
    if(mid>=pos)  add1(l,mid,tr[x].l,tr[y].l,pos);
    else   add1(mid+1,r,tr[x].r,tr[y].r,pos);
}
int query(int l,int r,int x,int y,int k)
{
    if(l==r)
    {
        if(k==1) return l;
        else return inf;
    }
    int mid=(l+r)>>1;
    int sum=tr[tr[y].l].sum-tr[tr[x].l].sum;
    if(sum>=k)  return query(l,mid,tr[x].l,tr[y].l,k);
    else   return query(mid+1,r,tr[x].r,tr[y].r,k-sum);
}
struct SAM{
    int las=1,tot=1,ch[MAXN<<1][26],len[MAXN<<1],fa[MAXN<<1][19];
    int sz[MAXN<<1],id[MAXN<<1],cnt,fpos[MAXN<<1],er[MAXN<<1],num[MAXN<<1];
    void init()
    {
        FOR(i,1,tot) memset(ch[i],0,sizeof(ch[i])),head[i]=-1;
        las=tot=1;cnt=0;
    }
    inline void add(int c,int z)
    {
        int p=las;int np=las=++tot;
        len[np]=len[p]+1;fpos[np]=len[np];er[z]=np;
        for(;p&&!ch[p][c];p=fa[p][0]) ch[p][c]=np;
        if(!p) fa[np][0]=1;
        else
        {
            int q=ch[p][c];
            if(len[q]==len[p]+1) fa[np][0]=q;
            else
            {
                int nq=++tot;
                memcpy(ch[nq],ch[q],sizeof(ch[q]));
                len[nq]=len[p]+1;
                fa[nq][0]=fa[q][0];
                fpos[nq]=n+1;
                fa[q][0]=fa[np][0]=nq;
                for(;p&&ch[p][c]==q;p=fa[p][0]) ch[p][c]=nq;
            }
        }
    }
    void dfs(int u)
    {
        sz[u]=1;id[++cnt]=u;num[u]=cnt;
        for(int i=head[u];i!=-1;i=e[i].next)
        {
            dfs(e[i].to);
            sz[u]+=sz[e[i].to];
        }
    }
    void bz()
    {
        FOR(i,1,18)
         FOR(j,1,tot)
          fa[j][i]=fa[fa[j][i-1]][i-1];

    }
    int getsz(int u,int z)
    {
        FOL(i,18,0)
        {
            int v=fa[u][i];
            if(len[v]>=z) u=v;
        }
        return u;
    }
    inline void slove()
    {
        sa=0;
        FOR(i,2,tot) add2(fa[i][0],i);
        dfs(1);qw=0;bz();int ans;
        FOR(i,1,cnt) add1(1,n+1,rt[i],rt[i-1],fpos[id[i]]);
        while(q--)
        {
            si(l),si(r),si(k);
            int pos=getsz(er[r],r-l+1);
            ans=query(1,n+1,rt[num[pos]-1],rt[num[pos]+sz[pos]-1],k);
            if(ans>=n+1) ans=-1;
            if(ans!=-1) ans-=(r-l);
            printf("%d\n",ans);
        }
    }
}sam;
int main()
{
    cin.tie(0);
    cout.tie(0);
    int t;
    cin>>t;
    REW(head,-1);
    while(t--)
    {
        sam.init();
        cin>>n>>q;ss(a);
        for(int i=0;i<n;i++) sam.add(a[i]-'a',i+1);
        sam.slove();
    }
    return 0;
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章