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<len<=300000

这道题非常容易想到把每个串翻转然后建立trie树,这样就把对于后缀的询问,转化成了在trie树上查询子树
然后可以用dfs序处理,再用可持久化线段树维护区间第k大值。。。
  1 #include<iostream>
  2 #include<cstdlib>
  3 #include<cmath>
  4 #include<cstring>
  5 #include<cstdio>
  6 #include<algorithm>
  7 #include<string>
  8 #include<map>
  9 #include<queue>
 10 #include<vector>
 11 #include<set>
 12 #define inf 1000000000
 13 #define maxn 300000+5
 14 #define maxm 1000000+5
 15 #define eps 1e-10
 16 #define ll long long
 17 #define for0(i,n) for(int i=0;i<=(n);i++)
 18 #define for1(i,n) for(int i=1;i<=(n);i++)
 19 #define for2(i,x,y) for(int i=(x);i<=(y);i++)
 20 #define for3(i,x,y) for(int i=(x);i>=(y);i--)
 21 #define for4(i,x) for(int i=head[x],y=e[i].go;i;i=e[i].next,y=e[i].go)
 22 using namespace std;
 23 int read(){
 24     int x=0,f=1;char ch=getchar();
 25     while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
 26     while(ch>='0'&&ch<='9'){x=10*x+ch-'0';ch=getchar();}
 27     return x*f;
 28 }
 29 int trie[maxn][26],o=1,fa[maxn];
 30 vector<int> en[maxn];
 31 int nx[100005],root[600005],lch[4*maxm],rch[4*maxm],num[4*maxm],x=0;
 32 int dfn[maxn][2],now=0,n;
 33 char a[300005];
 34 int insert(int i,int l,int r,int j){
 35     x++;
 36     int t=x;
 37     lch[t]=lch[i];
 38     rch[t]=rch[i];
 39     num[t]=num[i]+1;
 40     if(l!=r){
 41         int mid=(l+r)>>1;
 42         if(j>mid) rch[t]=insert(rch[i],mid+1,r,j);
 43         else lch[t]=insert(lch[i],l,mid,j);
 44     }
 45     return t;
 46 }
 47 int dfs(int x){
 48     now++;
 49     int sz=en[x].size(),rt=root[now-1];
 50     for0(i,sz-1)
 51         rt=insert(rt,1,n,en[x][i]);
 52     root[now]=rt;
 53     dfn[x][0]=now;
 54     for0(i,25)
 55         if(trie[x][i])
 56             dfs(trie[x][i]);
 57     now++;
 58     dfn[x][1]=now;
 59     root[now]=root[now-1]; 
 60 }
 61 int get(int i,int j,int k){
 62     i=root[i-1],j=root[j];
 63     if(num[j]-num[i]<k)
 64         return -1;
 65     int l=1,r=n;
 66     while(l!=r){
 67         int mid=(l+r)>>1;
 68         if(num[lch[j]]-num[lch[i]]>=k){
 69             r=mid;
 70             i=lch[i];
 71             j=lch[j];
 72         }
 73         else{
 74             k-=num[lch[j]]-num[lch[i]];
 75             l=mid+1;
 76             i=rch[i];
 77             j=rch[j];
 78         }
 79     }
 80     return l;
 81 }
 82 int main(){
 83     //freopen("input.txt","r",stdin);
 84     //freopen("output.txt","w",stdout);
 85     n=read();
 86     for1(i,n){
 87         scanf("%s",a);
 88         int len=strlen(a);
 89         for0(j,(len-2)/2)
 90             swap(a[j],a[len-j-1]);
 91         int p=1;
 92         for0(j,len-1){
 93             if(trie[p][a[j]-'a']==0){
 94                 o++;
 95                 trie[p][a[j]-'a']=o;
 96                 fa[o]=p;
 97             }
 98             p=trie[p][a[j]-'a'];
 99             if(j==len-1){
100                 nx[i]=p;
101                 en[p].push_back(i);        
102             }
103         }
104     }
105     dfs(1);
106     for1(i,n){
107         int x=read();
108         printf("%d\n",get(dfn[nx[i]][0],dfn[nx[i]][1],x));
109     }
110     return 0;
111 }
View Code

 

posted @ 2016-06-16 11:42  HTWX  阅读(170)  评论(0编辑  收藏  举报