【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小的数,用主席树解决。
代码如下:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
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\n",ffind(t[wh[i]].dfn,t[wh[i]].rh,k[i])); 153 } 154 return 0; 155 }
2016-08-24 11:03:11