K-th occurrence 2019CCPC網絡賽+HDU6704(後綴自動機+主席樹)

K-th occurrence

之前網絡賽跟隊友合體出的題,當時我寫的後綴自動機,他寫的主席樹,hhh!
現在我會寫主席樹,他會寫後綴數組,於是各自獨立的A了!並且我跟之前網絡賽時的解法還不完全一樣

巨佬隊友bxd的後綴數組+主席樹解法

題意:

給定一個串SS,有QQ個詢問:求子串S[l,r]S[l,r]SS中的第kk次出現位置。

思路:

  1. 由於後綴自動機可以知道某個子串的endposendpos集合,顯然此題至少有暴力的做法。
  2. 首先,得找到最短的包含所詢問的子串的節點,然後其所在parentparent treetree的子樹就是所有endposendpos的集合。那麼,如何快速找到這個節點呢?在構建後綴自動機時考慮每插入一個字符,就記錄下這個節點所代表的最長子串屬於對應字符串的哪個位置,並進行雙向鏈接。通過rr的這個鏈接就可以找到那個節點;找到後通過倍增就可以在O(logn)O(logn)時間內找到這個最短的包含所詢問的子串的節點。
  3. 然後如何處理子樹中第kk小權值呢?一個常見套路就是在樹的dfsdfs序上建主席樹!ThenThen,問題基本得到解決。
  4. 有個細節就是判斷什麼條件輸出1-1,這裏有兩種處理:
    處理11:我們想要的是那個子樹的節點數大於等於kk即可,但是考慮到虛點的存在,我們再dfsdfs序上建主席樹時,不要插入虛點即可。
    處理22:計算每個節點的cntcnt值,然後提前判斷找到的節點的cntcnt值是否大於等於kk即可。(這是比賽時的做法)

剛剛寫好的代碼

#include "bits/stdc++.h"
#define hhh printf("hhh\n")
#define see(x) (cerr<<(#x)<<'='<<(x)<<endl)
using namespace std;
typedef long long ll;
typedef pair<int,int> pr;
inline int read() {int x=0,f=1;char c=getchar();while(c!='-'&&(c<'0'||c>'9'))c=getchar();if(c=='-')f=-1,c=getchar();while(c>='0'&&c<='9')x=x*10+c-'0',c=getchar();return f*x;}

const int maxn = 2e5+10;
const int inf = 0x3f3f3f3f;
const int mod = 1e9+7;
const double eps = 1e-7;

char s[maxn];
int N, Q;
int ch[maxn][26], len[maxn], endpos[maxn], rpos[maxn];
int last, tot;
int fa[maxn], st[maxn][18];
int head[maxn], to[maxn], nxt[maxn], edge;
int id[maxn], rk[maxn], sz[maxn], ID;
int rt[maxn], node[maxn<<5], ls[maxn<<5], rs[maxn<<5], cnt;

inline void add_edge(int u, int v) {
    ++edge; to[edge]=v; nxt[edge]=head[u]; head[u]=edge;
}

void add(int c) {
    int p=last, np=last=++tot;
    rpos[endpos[np]=len[np]=len[p]+1]=np;
    for(; p&&!ch[p][c]; p=fa[p]) ch[p][c]=np;
    if(!p) fa[np]=st[np][0]=1;
    else {
        int q=ch[p][c];
        if(len[q]==len[p]+1) fa[np]=st[np][0]=q;
        else {
            int nq=++tot; len[nq]=len[p]+1;
            st[nq][0]=fa[nq]=fa[q]; st[q][0]=st[np][0]=fa[q]=fa[np]=nq;
            memcpy(ch[nq],ch[q],104);
            for(; p&&ch[p][c]==q; p=fa[p]) ch[p][c]=nq;
            endpos[nq]=0;
        }
    }
}

void dfs(int u) {
    rk[id[u]=++ID]=u; sz[u]=1;
    for(int i=head[u]; i; i=nxt[i]) dfs(to[i]), sz[u]+=sz[to[i]];
}

int get_pos(int length, int r) {
    int x=rpos[r];
    for(int i=17; i>=0; --i) if(len[st[x][i]]>=length) x=st[x][i];
    return x;
}

void update(int x, int l, int r, int pre, int &now) {
    now=++cnt;
    node[now]=node[pre]+1; ls[now]=ls[pre]; rs[now]=rs[pre];
    if(l==r) return;
    int m=(l+r)/2;
    if(x<=m) update(x,l,m,ls[pre],ls[now]);
    else update(x,m+1,r,rs[pre],rs[now]);
}

int query(int k, int l, int r, int x, int y) {
    if(l==r) return l;
    int s=node[y]-node[x], sl=node[ls[y]]-node[ls[x]];
    if(s<k) return -1;
    int m=(l+r)/2;
    if(sl>=k) return query(k,l,m,ls[x],ls[y]);
    return query(k-sl,m+1,r,rs[x],rs[y]);
}

int main() {
    int T=read();
    while(T--) {
        last=tot=1;
        N=read(), Q=read();
        scanf("%s", s+1);
        for(int i=1; s[i]; ++i) add(s[i]-'a');
        for(int i=2; i<=tot; ++i) add_edge(fa[i],i);
        dfs(1);
        for(int j=1; j<18; j++)
            for(int i=1; i<=tot; ++i) st[i][j]=st[st[i][j-1]][j-1];
        for(int i=1; i<=tot; ++i) {
            if(endpos[rk[i]]) update(endpos[rk[i]],1,N,rt[i-1],rt[i]);
            else rt[i]=rt[i-1];
        }
        while(Q--) {
            int l=read(), r=read(), k=read();
            int p=get_pos(r-l+1,r);
            int ans=query(k,1,N,rt[id[p]-1],rt[id[p]-1+sz[p]]);
            if(ans==-1) printf("-1\n");
            else printf("%d\n", ans-r+l);
        }
        for(int i=1; i<=tot; ++i) memset(ch[i],0,sizeof(ch[i])), head[i]=0;
        cnt=ID=edge=0;
    }
}

比賽時寫的代碼

//#pragma comment(linker, "/STACK:102400000,102400000")
#include "bits/stdc++.h"
#define pb push_back
#define ls l,m,now<<1
#define rs m+1,r,now<<1|1
#define hhh printf("hhh\n")
#define see(x) (cerr<<(#x)<<'='<<(x)<<endl)
using namespace std;
typedef long long ll;
typedef pair<int,int> pr;
inline int read() {int x=0;char c=getchar();while(c<'0'||c>'9')c=getchar();while(c>='0'&&c<='9')x=x*10+c-'0',c=getchar();return x;}

const int N = 2e5+10;
const int mod = 1e9+7;
const double eps = 1e-9;

struct Edge{int to, nex;}edge[N];

int t[N<<5],node[N],id[N],dep[N],fa[N],top[N],son[N],siz[N],ncnt,w[N],pos,head[N],n,m,ans,lson[N<<5],rson[N<<5],T[N],tot;

char s[N];
int ch[N][26], len[N], rk[N], endpos[N];
int par[N][20];
int last, sz;
int c[N], a[N], cnt[N], lg[N];
int NN, Q, l, r, k;

inline void add(int a, int b) { edge[++pos].nex=head[a]; edge[pos].to=b; head[a]=pos; }

////////////////////
void build(int l,int r,int &pos)
{
    pos=++ncnt;
    t[pos]=0;
    if(l==r)return ;
    int m=(l+r)>>1;
    build(l,m,lson[pos]);
    build(m+1,r,rson[pos]);
}


void up(int x,int l,int r,int pre,int &pos)
{
    pos=++ncnt;
    lson[pos]=lson[pre];rson[pos]=rson[pre];
    t[pos]=t[pre]+1;
    if(l==r)return ;int m=(l+r)>>1;
    if(x<=m)up(x,l,m,lson[pre],lson[pos]);
    else up(x,m+1,r,rson[pre],rson[pos]);
}
int qk(int k,int l,int r,int pre,int pos)
{
    int x=t[lson[pos]]-t[lson[pre]];
    if(l==r)return l;
    int m=(l+r)>>1;
    if(k<=x)return qk(k,l,m,lson[pre],lson[pos]);
    else return qk(k-x,m+1,r,rson[pre],rson[pos]);
}

void dfs1(int x,int f)
{
    fa[x]=f;dep[x]=dep[fa[x]]+1;son[x]=0;siz[x]=1;
    for(int i=head[x];i;i=edge[i].nex)
    {
        int v=edge[i].to;
        if(v==fa[x])continue;
        dfs1(v,x);siz[x]+=siz[v];
        if(siz[son[x]]<siz[v])son[x]=v;
    }
}
void dfs2(int x,int topf)
{
    top[x]=topf;id[x]=++tot;

    up(endpos[x],1,NN,T[id[x]-1],T[id[x]]);

    if(son[x])dfs2(son[x],topf);
    for(int i=head[x];i;i=edge[i].nex)
    {
        int v=edge[i].to;
        if(v==son[x]||v==fa[x])continue;
        dfs2(v,v);
    }
}
////////////////

void add_p(int c, int pos) {
    int p=last, np=last=++sz;
    len[np]=len[p]+1, cnt[np]=1, endpos[np]=pos, rk[pos]=np;
    for(; p&&!ch[p][c]; p=fa[p]) ch[p][c]=np;
    if(!p) fa[np]=1;
    else {
        int q=ch[p][c];
        if(len[q]==len[p]+1) fa[np]=q;
        else {
            int nq=++sz; endpos[nq]=NN;
            fa[nq]=fa[q], len[nq]=len[p]+1;
            memcpy(ch[nq],ch[q],104);
            fa[q]=fa[np]=nq;
            for(; p&&ch[p][c]==q; p=fa[p]) ch[p][c]=nq;
        }
    }
}

void solve(int l, int r, int k) {
    int p=rk[r], nl=r-l+1;

    //while(p&&len[fa[p]]>=nl) p=fa[p];
    for(int i=19; i>=0; --i) {
        if(len[par[p][i]]>=nl) {
            p=par[p][i];
        }
    }
    if(cnt[p]<k) printf("-1\n");
    else {
        printf("%d\n", qk(k,1,NN,T[id[p]-1],T[id[p]+siz[p]-1])-nl+1);
    }
}

int main() {
    //ios::sync_with_stdio(false);
    for(int i=1; i<N; ++i) lg[i]=lg[i-1]+(1<<lg[i-1]==i);
    int TT=read();
    while(TT--) {
        NN=read(), Q=read();
        scanf("%s", s+1);
        //reverse(s+1,s+1+NN);

        last=sz=1;
        ncnt=tot=pos=0;
        build(1,NN,T[0]);

        for(int i=1; i<=NN; ++i) add_p(s[i]-'a',i);

        for(int i=1; i<=sz; ++i) c[len[i]]++;
        for(int i=1; i<=sz; ++i) c[i]+=c[i-1];
        for(int i=1; i<=sz; ++i) a[c[len[i]]--]=i;
        for(int i=sz; i; --i) cnt[fa[a[i]]]+=cnt[a[i]]; cnt[1]=0;
        for(int i=1; i<=sz; ++i) {
            add(fa[i],i);
        }
        endpos[1]=endpos[0]=NN;

        dfs1(1,0);
        dfs2(1,1);

        for(int i=1; i<=sz; ++i) par[i][0]=fa[i];
        for(int k=1; k<20; ++k)
            for(int i=1; i<=sz; ++i)
                par[a[i]][k]=par[par[a[i]][k-1]][k-1];
        while(Q--) {
            l=read(), r=read(), k=read();
            solve(l,r,k);
        }
        for(int i=0; i<=sz; ++i) {
            c[i]=a[i]=len[i]=fa[i]=cnt[i]=rk[i]=endpos[i]=head[i]=0;
            for(int j=0; j<26; ++j) ch[i][j]=0;
            for(int j=0; j<20; ++j) par[i][j]=0;
        }
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章