• 【BZOJ3439】 Kpm的MC密码 (TRIE+主席树)


    3439: Kpm的MC密码

    Description


     背景

        想Kpm当年为了防止别人随便进入他的MC,给他的PC设了各种奇怪的密码和验证问题(不要问我他是怎么设的。。。),于是乎,他现在理所当然地忘记了密码,只能来解答那些神奇的身份验证问题了。。。

     描述

        Kpm当年设下的问题是这样的:

        现在定义这么一个概念,如果字符串s是字符串c的一个后缀,那么我们称c是s的一个kpm串。

        系统将随机生成n个由a…z组成的字符串,由1…n编号(s1,s2…,sn),然后将它们按序告诉你,接下来会给你n个数字,分别为k1…kn,对于每一个ki,要求你求出列出的n个字符串中所有是si的kpm串的字符串的编号中第ki小的数,如果不存在第ki小的数,则用-1代替。(比如说给出的字符串是cd,abcd,bcd,此时k1=2,那么”cd”的kpm串有”cd”,”abcd”,”bcd”,编号分别为1,2,3其中第2小的编号就是2)(PS:如果你能在相当快的时间里回答完所有n个ki的查询,那么你就可以成功帮kpm进入MC啦~~)

    Input

        第一行一个整数 n 表示字符串的数目

        接下来第二行到n+1行总共n行,每行包括一个字符串,第i+1行的字符串表示编号为i的字符串

        接下来包括n行,每行包括一个整数ki,意义如上题所示

    Output

        包括n行,第i行包括一个整数,表示所有是si的kpm串的字符串的编号中第ki小的数

    Sample Input


    3
    cd
    abcd
    bcd
    2
    3
    1

    Sample Output

    2
    -1
    2

    样例解释

    “cd”的kpm 串有”cd”,”abcd”,”bcd”,编号为1,2,3,第2小的编号是

    2,”abcd”的kpm串只有一个,所以第3小的编号不存在,”bcd”的kpm

    串有”abcd”,”bcd”,第1小的编号就是2。

    数据范围与约定

    设所有字符串的总长度为len


    对于100%的数据,1<=n<=100000,0
     
     
    【题意】
      

      给n(10^5)个字符串,总长(10^5),每个字符串给出ki。对于每个字符串si,把每个存在后缀为si的字符串拿出来,其中编号第ki小的就是si的答案。将每个字符串的答案输出。

    【分析】

      把字符串反过来建一颗字典树,那么它子树上的就都和和他同后缀。求出dfs序,问题就转化成区间第k小的数,用主席树解决。

    代码如下:

      1 #include<cstdio>
      2 #include<cstdlib>
      3 #include<cstring>
      4 #include<iostream>
      5 #include<algorithm>
      6 #include<queue>
      7 using namespace std;
      8 #define Maxn 100010
      9 #define Maxd 20
     10 
     11 struct node
     12 {
     13     int x,f,p,dfn,rh;
     14     int son[30];
     15 }t[Maxn];
     16 
     17 void upd(int x)
     18 {
     19     t[x].p=0;
     20     memset(t[x].son,0,sizeof(t[x].son));
     21 }
     22 
     23 char s[Maxn];
     24 int n,nt[Maxn],tot;
     25 int wh[Maxn],k[Maxn];
     26 
     27 int mymax(int x,int y) {return x>y?x:y;}
     28 
     29 void init()
     30 {
     31     scanf("%d",&n);
     32     upd(0);tot=0;
     33     for(int i=1;i<=n;i++)
     34     {
     35         scanf("%s",s);
     36         int l=strlen(s);
     37         int now=0;
     38         for(int j=l-1;j>=0;j--)
     39         {
     40             int ind=s[j]-'a'+1;
     41             if(!t[now].son[ind])
     42             {
     43                 t[now].son[ind]=++tot;
     44                 upd(tot);t[tot].f=now;
     45             }
     46             now=t[now].son[ind];
     47             if(j==0)
     48             {
     49                 nt[i]=t[now].p;
     50                 t[now].p=i;
     51                 wh[i]=now;
     52             }
     53         }
     54     }
     55     for(int i=1;i<=n;i++) scanf("%d",&k[i]);
     56 }
     57 
     58 
     59 int cnt,df[Maxn];
     60 void dfs(int x)
     61 {
     62     t[x].dfn=t[x].rh=++cnt;df[cnt]=x;
     63     for(int i=1;i<=26;i++) if(t[x].son[i])
     64     {
     65         dfs(t[x].son[i]);
     66         t[x].rh=t[t[x].son[i]].rh;
     67     }
     68 }
     69 
     70 int rt[Maxn],sum;
     71 struct hp
     72 {
     73     int son[2],cnt;
     74 }a[Maxn*Maxd];
     75 
     76 void dfs2(int l,int x,int dep)
     77 {
     78     if(dep==0) return;
     79     if(a[x].son[0]) dfs2(a[l].son[0],a[x].son[0],dep-1);
     80     else a[x].son[0]=a[l].son[0];
     81     if(a[x].son[1]) dfs2(a[l].son[1],a[x].son[1],dep-1);
     82     else a[x].son[1]=a[l].son[1];
     83 }
     84 
     85 void build()
     86 {
     87     sum=0;
     88     a[0].son[0]=a[0].son[1]=a[0].cnt=0;
     89     rt[0]=0;
     90     for(int i=1;i<=tot;i++)
     91     {
     92         rt[i]=++sum;
     93         int l,r;
     94         l=rt[i-1],r=sum;
     95         a[rt[i]].cnt=a[rt[i-1]].cnt;
     96         for(int j=t[df[i]].p;j;j=nt[j])
     97         {
     98             int x=j;
     99             a[rt[i]].cnt++;
    100             l=rt[i-1];r=rt[i];
    101             for(int kk=17;kk>=1;kk--)
    102             {
    103                 int ind=x/(1<<kk-1);
    104                 x%=(1<<kk-1);
    105                 l=a[l].son[ind];
    106                 if(!a[r].son[ind])
    107                 {
    108                     a[r].son[ind]=++sum;
    109                     a[sum].cnt=a[l].cnt;
    110                     a[sum].son[0]=a[sum].son[1]=0;
    111                 }
    112                 r=a[r].son[ind];
    113                 a[r].cnt++;
    114             }
    115         }
    116         dfs2(rt[i-1],rt[i],17);
    117     }
    118 }
    119 
    120 int ffind(int l,int r,int kk)
    121 {
    122     l--;
    123     l=rt[l];r=rt[r];
    124     int ans=0;
    125     if(a[r].cnt-a[l].cnt<kk) return -1;
    126     for(int i=17;i>=1;i--)
    127     {
    128         if(a[a[r].son[0]].cnt-a[a[l].son[0]].cnt>=kk)
    129         {
    130             l=a[l].son[0];
    131             r=a[r].son[0];
    132         }
    133         else
    134         {
    135             kk-=a[a[r].son[0]].cnt-a[a[l].son[0]].cnt;
    136             l=a[l].son[1];
    137             r=a[r].son[1];
    138             ans+=(1<<i-1);
    139         }
    140     }
    141     return ans;
    142 }
    143 
    144 int main()
    145 {
    146     init();
    147     cnt=-1;
    148     dfs(0);
    149     build();
    150     for(int i=1;i<=n;i++)
    151     {
    152         printf("%d
    ",ffind(t[wh[i]].dfn,t[wh[i]].rh,k[i]));
    153     }
    154     return 0;
    155 }
    [BZOJ3439]

    2016-08-24 11:03:11

  • 相关阅读:
    切割窗口url
    软键盘弹出底部被顶上去
    C语言字符串处理标准库函数的源码(转)
    slapd配置文件详述
    OPENLDAP安装配置方法
    const成员函数
    OPENLDAP概述
    当前比较有名的Xml数据库
    『转』使用 Scalable Vector Graphics 为 ASP.NET 构建基于 XML 的灵活、轻量的图像
    SqlCommand_ExecuteNonQuery 方法返回值为1的解释
  • 原文地址:https://www.cnblogs.com/Konjakmoyu/p/5802035.html
Copyright © 2020-2023  润新知