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啦~~)
题解:
这种题目都没有1A……我真是菜……容易想到把字符串反过来建字典树,然后每个查询就可以转化为在一颗子树中找第k小的值,那么容易想到dfs序+主席树,直接上就可以了。注意重复字符串的处理,我就是因为这个失去了1A……
代码:
#include<bits/stdc++.h>
using namespace std;
#define LL long long
const int Maxn=100010;
const int Maxl=300010;
int read()
{
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=(x<<3)+(x<<1)+(ch^48);ch=getchar();}
return x*f;
}
vector<int>m1[Maxl];
int n,m2[Maxn];
int root[Maxl],lc[6000000],rc[6000000],s[6000000],tot2=0;
int son[Maxl][27],tot1=0;
string str[Maxn];
struct Edge{int y,next;}e[Maxl];
int last[Maxl],len=0;
void ins(int x,int y){int t=++len;e[t].y=y;e[t].next=last[x];last[x]=t;}
void build(int o)
{
int now=0;
for(int i=0;i<str[o].size();i++)
{
int x=str[o][i]-'a';
if(!son[now][x])son[now][x]=++tot1,ins(now,tot1);
now=son[now][x];
}
m1[now].push_back(o);
m2[o]=now;
}
void Ins(int &u,int l,int r,int p)
{
if(!u)u=++tot2;
s[u]++;if(l==r)return;
int mid=l+r>>1;
if(p<=mid)Ins(lc[u],l,mid,p);else Ins(rc[u],mid+1,r,p);
}
void merge(int &u1,int u2)
{
if(!u1){u1=u2;return;}
if(!u2)return;
s[u1]+=s[u2];
merge(lc[u1],lc[u2]);merge(rc[u1],rc[u2]);
}
int query(int rt1,int rt2,int l,int r,int k)//第k小
{
if(s[rt1]-s[rt2]<k)return -1;
if(l==r)return l;
int c=s[lc[rt1]]-s[lc[rt2]],mid=l+r>>1;
if(k<=c)return query(lc[rt1],lc[rt2],l,mid,k);
else return query(rc[rt1],rc[rt2],mid+1,r,k-c);
}
int in[Maxl],out[Maxl],dfn=0;
void dfs(int x)
{
in[x]=++dfn;
if(m1[x].size())
for(int i=0;i<m1[x].size();i++)Ins(root[in[x]],1,n,m1[x][i]);
for(int i=last[x];i;i=e[i].next)dfs(e[i].y);
out[x]=dfn;
}
int main()
{
n=read();
for(int i=1;i<=n;i++)
{
cin>>str[i];
reverse(str[i].begin(),str[i].end());
build(i);
}
dfs(0);root[0]=0;
for(int i=1;i<=dfn;i++)merge(root[i],root[i-1]);
for(int i=1;i<=n;i++)
{
int k=read();
printf("%d\n",query(root[out[m2[i]]],root[in[m2[i]]-1],1,n,k));
}
}