zoukankan      html  css  js  c++  java
  • BZOJ3439: Kpm的MC密码

    【传送门:BZOJ3439


    简要题意:

      给出n个字符串,给出ki,求出以每个字符串为后缀的字符串中的编号为ki的字符串,如果没有则输出-1


    题解:

      倒着把字符串插进字典树里,这样子就可以保证一个点是它的子树的所有点的后缀(字典树里一个点代表一个字符串)

      然后跑一遍dfs,求dfs序,然后用主席树求出每个字符串的最下面的点的子树内第k小的值就行了


    参考代码:

    #include<cstdio>
    #include<cstring>
    #include<cstdlib>
    #include<algorithm>
    #include<cmath>
    using namespace std;
    struct trnode
    {
        int lc,rc,c;
    }tr[11000000];int trlen,rt[810000];
    void Link(int &u,int l,int r,int p)
    {
        if(u==0) u=++trlen;
        tr[u].c++;
        if(l==r) return ;
        int mid=(l+r)/2;
        if(p<=mid) Link(tr[u].lc,l,mid,p);
        else Link(tr[u].rc,mid+1,r,p);
    }
    void Merge(int &u1,int u2)
    {
        if(u1==0){u1=u2;return ;}
        if(u2==0) return ;
        tr[u1].c+=tr[u2].c;
        Merge(tr[u1].lc,tr[u2].lc);
        Merge(tr[u1].rc,tr[u2].rc);
    }
    int findkth(int u1,int u2,int l,int r,int k)
    {
        if(l==r) return l;
        if(tr[u1].c-tr[u2].c<k) return -1;
        int c=tr[tr[u1].lc].c-tr[tr[u2].lc].c,mid=(l+r)/2;
        if(c>=k) return findkth(tr[u1].lc,tr[u2].lc,l,mid,k);
        else return findkth(tr[u1].rc,tr[u2].rc,mid+1,r,k-c);
    }
    struct trie
    {
        int c[27],s;
        trie()
        {
            s=0;
            memset(c,-1,sizeof(c));
        }
    }t[810000];int tot;
    char st[810000];
    int L[810000],R[810000],ys[810000],z;
    int w[810000];
    int n;
    int pre[810000];
    void bt(int d)
    {
        int x=0,len=strlen(st+1);
        for(int i=len;i>=1;i--)
        {
            int y=st[i]-'a'+1;
            if(t[x].c[y]==-1) t[x].c[y]=++tot;
            x=t[x].c[y];
        }
        if(t[x].s==0) t[x].s=d;
        else pre[d]=t[x].s,t[x].s=d; 
        w[d]=x;
    }
    void dfs(int x)
    {
        L[x]=++z;ys[x]=z;
        if(t[x].s!=0)
        {
            Link(rt[z],1,n,t[x].s);
            int j=t[x].s;
            while(pre[j]!=0)
            {
                j=pre[j];
                Link(rt[z],1,n,j);
            }
        }
        for(int i=1;i<=26;i++)
        {
            if(t[x].c[i]!=-1)
            {
                dfs(t[x].c[i]);
            }
        }
        R[x]=z;
    }
    int main()
    {
        scanf("%d",&n);
        for(int i=1;i<=n;i++)
        {
            scanf("%s",st+1);
            bt(i);
        }
        z=0;dfs(0);
        for(int i=1;i<=z;i++) Merge(rt[i],rt[i-1]);
        for(int i=1;i<=n;i++)
        {
            int k;
            scanf("%d",&k);
            printf("%d
    ",findkth(rt[R[w[i]]],rt[L[w[i]]-1],1,n,k));
        }
        return 0;
    }

     

  • 相关阅读:
    四 闭包函数、装饰器
    三 名称空间与作用域
    二 函数对象、函数嵌套
    一 函数定义
    函数路线
    Django_rest_framework分页
    Django Rest framework序列化流程
    Django Rest framework的限流实现流程
    mysql 数据库查看表的信息
    java JDBC编程流程步骤
  • 原文地址:https://www.cnblogs.com/Never-mind/p/8866804.html
Copyright © 2011-2022 走看看