您的位置:首页 > 产品设计 > 产品经理

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

2016-08-24 10:59 323 查看

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小的数,用主席树解决。

代码如下:

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<queue>
using namespace std;
#define Maxn 100010
#define Maxd 20

struct node
{
int x,f,p,dfn,rh;
int son[30];
}t[Maxn];

void upd(int x)
{
t[x].p=0;
memset(t[x].son,0,sizeof(t[x].son));
}

char s[Maxn];
int n,nt[Maxn],tot;
int wh[Maxn],k[Maxn];

int mymax(int x,int y) {return x>y?x:y;}

void init()
{
scanf("%d",&n);
upd(0);tot=0;
for(int i=1;i<=n;i++)
{
scanf("%s",s);
int l=strlen(s);
int now=0;
for(int j=l-1;j>=0;j--)
{
int ind=s[j]-'a'+1;
if(!t[now].son[ind])
{
t[now].son[ind]=++tot;
upd(tot);t[tot].f=now;
}
now=t[now].son[ind];
if(j==0)
{
nt[i]=t[now].p;
t[now].p=i;
wh[i]=now;
}
}
}
for(int i=1;i<=n;i++) scanf("%d",&k[i]);
}

int cnt,df[Maxn];
void dfs(int x)
{
t[x].dfn=t[x].rh=++cnt;df[cnt]=x;
for(int i=1;i<=26;i++) if(t[x].son[i])
{
dfs(t[x].son[i]);
t[x].rh=t[t[x].son[i]].rh;
}
}

int rt[Maxn],sum;
struct hp
{
int son[2],cnt;
}a[Maxn*Maxd];

void dfs2(int l,int x,int dep)
{
if(dep==0) return;
if(a[x].son[0]) dfs2(a[l].son[0],a[x].son[0],dep-1);
else a[x].son[0]=a[l].son[0];
if(a[x].son[1]) dfs2(a[l].son[1],a[x].son[1],dep-1);
else a[x].son[1]=a[l].son[1];
}

void build()
{
sum=0;
a[0].son[0]=a[0].son[1]=a[0].cnt=0;
rt[0]=0;
for(int i=1;i<=tot;i++)
{
rt[i]=++sum;
int l,r;
l=rt[i-1],r=sum;
a[rt[i]].cnt=a[rt[i-1]].cnt;
for(int j=t[df[i]].p;j;j=nt[j])
{
int x=j;
a[rt[i]].cnt++;
l=rt[i-1];r=rt[i];
for(int kk=17;kk>=1;kk--)
{
int ind=x/(1<<kk-1);
x%=(1<<kk-1);
l=a[l].son[ind];
if(!a[r].son[ind])
{
a[r].son[ind]=++sum;
a[sum].cnt=a[l].cnt;
a[sum].son[0]=a[sum].son[1]=0;
}
r=a[r].son[ind];
a[r].cnt++;
}
}
dfs2(rt[i-1],rt[i],17);
}
}

int ffind(int l,int r,int kk)
{
l--;
l=rt[l];r=rt[r];
int ans=0;
if(a[r].cnt-a[l].cnt<kk) return -1;
for(int i=17;i>=1;i--)
{
if(a[a[r].son[0]].cnt-a[a[l].son[0]].cnt>=kk)
{
l=a[l].son[0];
r=a[r].son[0];
}
else
{
kk-=a[a[r].son[0]].cnt-a[a[l].son[0]].cnt;
l=a[l].son[1];
r=a[r].son[1];
ans+=(1<<i-1);
}
}
return ans;
}

int main()
{
init();
cnt=-1;
dfs(0);
build();
for(int i=1;i<=n;i++)
{
printf("%d\n",ffind(t[wh[i]].dfn,t[wh[i]].rh,k[i]));
}
return 0;
}


[BZOJ3439]

2016-08-24 11:03:11
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: