【BZOJ3439】Kpm的MC密碼

題目鏈接:BZOJ3439

(tips:題目條件沒給全,底下所有字符串的長度之和大約不超過5×1055×10^5)

解法:字典樹+主席樹

先設法找到一個求kpm串的方法。按讀入的串反序構造字典樹,稱一個字符串的尾節點爲其在樹中的路徑中深度最大的那個點,記爲tst_s。那麼一個字符串ss的所有kmp串的尾節點全部位於以tst_s爲根的子樹內。
題目轉化爲求任意子樹內權值第kk大(注意有些節點不是任何字符串的尾節點,所以它的權值是空的,設成++\infty)。
然後給所有節點編上dfs序,主席樹維護即可。
時間複雜度O(m+(m+n)logn)O(m+(m+n)\log n)mm爲字符串總長)

代碼

#include<iostream>
#include<cstdio>
#include<cstring>
#include<vector>
 
using namespace std;
 
const int N=13000001,M=100001,S=500001;
int root=1,tot,tot0=1,idx,dfn[M],lst[M],sum[N],lson[N],rson[N],son[S][26],pos[M],n,rt[S],k,nod[S];
char str[S];
vector<int> id[S];
 
inline int create(int x){sum[++tot]=sum[x],lson[tot]=lson[x],rson[tot]=rson[x];return tot;}
 
void insert(char *str,int j){
    int u=root,m=strlen(str+1);
    for(int i=m;i;--i){int &v=son[u][str[i]-'a'];if(!v)v=++tot0;u=v;}
    id[u].push_back(j),pos[j]=u;
}
 
void dfs(int u){
    nod[dfn[u]=++idx]=u;
    for(int i=0;i<26;++i)if(son[u][i])dfs(son[u][i]);
    lst[u]=idx;
}
 
void update(int &o,int p,int l,int r,int k,int x){
    o=create(p);
    if(l==r){sum[o]=x;return;}
    int m=l+r>>1;if(m>=k)update(lson[o],lson[p],l,m,k,x);else update(rson[o],rson[p],m+1,r,k,x);
    sum[o]=sum[lson[o]]+sum[rson[o]];
}
 
void update2(int &o,int l,int r,int k){
    if(!o)o=++tot;
    if(l==r){sum[o]=1;return;}
    int m=l+r>>1;if(m>=k)update2(lson[o],l,m,k);else update2(rson[o],m+1,r,k);
    sum[o]=sum[lson[o]]+sum[rson[o]];
}
 
int query(int o,int p,int l,int r,int k){
    if(l==r)return l;
    int m=l+r>>1,d=sum[lson[p]]-sum[lson[o]];
    if(d>=k)return query(lson[o],lson[p],l,m,k);else return query(rson[o],rson[p],m+1,r,k-d);
}
 
int main(){
    scanf("%d",&n);
    for(int i=1;i<=n;++i)scanf("%s",str+1),insert(str,i);
    dfs(root);
    for(int i=1;i<=tot0;++i)if(!id[nod[i]].size())rt[i]=rt[i-1];else{
        update(rt[i],rt[i-1],1,n,id[nod[i]][0],1);
        for(int j=1;j<id[nod[i]].size();++j)update(rt[i],rt[i],1,n,id[nod[i]][j],1);
    }
    for(int i=1;i<=n;++i){
        scanf("%d",&k);
        if(sum[rt[lst[pos[i]]]]-sum[rt[dfn[pos[i]]-1]]<k){puts("-1");continue;}
        int x=query(rt[dfn[pos[i]]-1],rt[lst[pos[i]]],1,n,k);
        printf("%d\n",x);
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章