您的位置:首页 > 其它

GYM 101086 C.Everything(字典树)

2017-03-23 12:10 316 查看
Description

类似everything的搜索功能,所有字符串按字典序升序排,每次键入一个前缀光标就会移动到以该前缀为前缀的所有字符串中字典序最小的那个上面,每次键入一个字符串算一次操作,按一下上下键也算一次操作,给出n个串,问在everything中找到该串至少需要几步操作

Input

第一行一整数T表示用例组数,每组用例首先输入字符串数量n,之后n个全由小写字母组成的字符串,每个串串长不超过1e5,总串长不超过5e5(1<=T<=100,1<=n<=1e5)

Output

对于每组用例,输出n个整数,第i个数表示查询到第i个字符串至少几步操作

Sample Input

2

5

scpc

acm

syria

acpc

accepted

5

feglathegreat

candidatesamerraed

masterhossamyousef

candidateabdullahbahosain

masterhassanalhamsh

Sample Output

2 2 2 3 1

2 2 2 1 2

Solution

把所有串插入字典树中,对于每个串s的查询,设s串长为m,在字典树上dfs,不断增加要键入的前缀长度,对于每个前缀的最后一个字符x,有两种情况,一种是就键入x然后往下找,另一种是键入x+1然后往上找,所以在dfs的过程中要维护当前缀长度为i时字典序在s[1,i]前面的串数pre[i]和后面的串数next[i],已经键入长度为i的前缀时,往下找要找pre[m]-pre[i],故总操作数是i+pre[m]-pre[i],或者再键入s[i+1]+1然后往上找,往上要找next[m]-next[i],此时总操作数是i+1+next[m]-next[i],每层都拿这两个值更新一个最小值即可

Code

#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<vector>
#include<queue>
#include<map>
#include<set>
#include<ctime>
using namespace std;
typedef long long ll;
#define INF 0x3f3f3f3f
#define maxn 555555
int T,n,no,ch[maxn][26],id[maxn],cnt[maxn],sum[maxn],ans,Pre,Next;
char c[maxn],s[maxn];
void init()
{
memset(ch[0],-1,sizeof(ch[0]));
cnt[0]=0,id[0]=-1,no=0;
}
void insert(char *s,int _id)
{
int u=0;
cnt[0]++;
for(int i=0;s[i];i++)
{
int c=s[i]-'a';
if(ch[u][c]==-1)
{
ch[u][c]=++no;
memset(ch[no],-1,sizeof(ch[no]));
cnt[no]=0,id[no]=-1;
}
u=ch[u][c];
cnt[u]++;
}
id[u]=_id;
}
void dfs(int l,int r,int u,int pre,int next,int deep)
{
if(l==r)
{
ans=min(ans,deep),Pre=pre,Next=next+cnt[u]-1;
return ;
}
int c=s[l]-'a',tpre=pre,tnext=next;
for(int i=0;i<c;i++)
if(ch[u][i]!=-1)tpre+=cnt[ch[u][i]];
if(id[u]!=-1)tpre++;
for(int i=c+1;i<26;i++)
if(ch[u][i]!=-1)tnext+=cnt[ch[u][i]];
dfs(l+1,r,ch[u][c],tpre,tnext,deep+1);
ans=min(ans,deep+Pre-pre),ans=min(ans,deep+1+Next-next);
}
void Solve(int l,int r)
{
ans=INF,Pre=0,Next=0;
dfs(l,r,0,0,0,1);
}
int main()
{
scanf("%d",&T);
while(T--)
{
init();
scanf("%d",&n);
sum[0]=0;
for(int i=1;i<=n;i++)
{
scanf("%s",c);
int len=strlen(c);
insert(c,i);
sum[i]=sum[i-1]+len;
for(int j=sum[i-1];j<sum[i];j++)s[j]=c[j-sum[i-1]];
}
for(int i=1;i<=n;i++)
{
Solve(sum[i-1],sum[i]);
printf("%d%c",ans,i==n?'\n':' ');
}
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: