中石油个人训练 自动完成 APP(Tire树 + dfs序优化)

题目描述

奶牛 Bessie 很喜欢用手机上网聊天,但她的蹄子太大,经常会按到好几个键造成不必要的麻烦(丢死人了,你下辈子还是不要当奶牛了)。于是 Farmer John 给她专门设计了一套「自动完成 APP」。这个 APP 能够连接到在线词典来获取词库(词库的来源是 Bessie 常用的 n 个单词),并且有着自动补全的功能。当 Bessie 想打出她的一个常用单词时,她只需输入这个单词的某个前缀,并询问词库中拥有这个前缀的字典序第 k 小的单词,APP 就会返回这是词库中的第几个单词。
Farmer John 是个大忙人,所以编写 APP 的任务自然就交给了你。

 

输入

第一行两个整数 n,m,表示词库的单词个数和 Bessie 的询问次数。
接下来 n 行,每行一个字符串,表示 Bessie 的常用单词,输入的第 i 个字符串在词库中编号为 i。
接下来 m 行,每行一个整数 k 和一个字符串 S,表示 Bessie 的询问,意义是询问词库中以 S 为前缀的字典序第 k 小的单词在词库中的编号。

 

输出

对于每次询问输出一个整数,表示以S为前缀的字典序第 k 小的单词在词库中的编号;如果不存在这样的单词,输出 −1。

 看到题,一股字典树的套路感觉....于是敲了一个字典树,可惜T了

后来看题解,发现对于第k小字典序,可以先dfs整颗字典树,给每个串标号,然后在字典树走完串后直接输出下面的第k小即可.....

 

#include<bits/stdc++.h>
using namespace std;
#define Sheryang main
const int maxn=1e6+7;
typedef long long ll;
const int mod=1e9+7;
//#define getchar()(p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, 1 << 21, stdin), p1 == p2) ? EOF : *p1++)
//char buf[(1 << 21) + 1], *p1 = buf, *p2 = buf;
#define IO cin.tie(0),ios::sync_with_stdio(false);
#define pi acos(-1)
#define PII pair<ll,ll>
ll read(){ll c = getchar(),Nig = 1,x = 0;while(!isdigit(c) && c!='-')c = getchar();if(c == '-')Nig = -1,c = getchar();while(isdigit(c))x = ((x<<1) + (x<<3)) + (c^'0'),c = getchar();return Nig*x;}
#define read read()
/** keep hungry and keep calm! **/
 
struct node{
    int son[26],sz,end,id;
    int l,r;
}tire[maxn];
 
int tot = 1;
void ins(char *s,int id){
    int root = 1;
    tire[root].sz ++;
    for(int i=0;s[i];i++){
        int u = s[i] - 'a';
        if(tire[root].son[u] == 0){
            tire[root].son[u] = ++tot;
        }
        root = tire[root].son[u];
        tire[root].sz ++;
    }
    tire[root].end ++;
    tire[root].id = id;
}
 
int ans[maxn],cnt;
void dfs(int u){
    tire[u].l = cnt;
    if(tire[u].end){
        ans[cnt++] = tire[u].id;
    }
    for(int i=0;i<26;i++){
        if(tire[u].son[i]){
            dfs(tire[u].son[i]);
        }
    }
}
 
int solve(char *s,int k){
     
    int root = 1;
    for(int i=0;s[i];i++){
        int u = s[i] -'a';
        root = tire[root].son[u];
    }
    if(tire[root].sz < k) return -1;
    return ans[tire[root].l + k -1];
}
 
char s[maxn];
int Sheryang(){
     
    int n = read , Q = read;
     
    for(int i=1;i<=n;i++){
        scanf("%s",s);
        ins(s,i);
    }
    dfs(1);
    while(Q--){
        int k = read;
        scanf("%s",s);
        printf("%d\n",solve(s,k));
    }
    return 0;
}

 

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值