1. 程式人生 > >【洛谷P2922】Secret Message

【洛谷P2922】Secret Message

順序 sage bits pac 代碼 mes namespace 節點 記錄

題目大意:給定 N 個字符串組成的字典,有 M 個詢問,每次給定一個字符串,求字典中有多少個單詞為給定字符串的前綴或前綴是給定的字符串。

題解:在 trie 上維護一個 tag 表示有多少字符串以當前字符串為前綴,ed 表示從該節點到根節點之間為一個字符串。
對於給定的字符串,在 trie 中順序查找,在匹配的過程中累加經過節點的 ed 標記,表示有多少字符串為給定字符串的前綴。若匹配成功,則答案累加 tag 標記並減去最後一個節點的 ed 標記,防止重復計算。若匹配失敗,只需輸出記錄的 ed 之和即可。

代碼如下

#include <bits/stdc++.h>
using namespace std;
const int maxn=5e5+10;

int trie[maxn][2],tot=1,tag[maxn],ed[maxn];
int m,n,len,s[10010];

void insert(int *ss){
    int now=1;
    for(int i=1;i<=len;i++){
        int ch=ss[i];
        if(!trie[now][ch])trie[now][ch]=++tot;
        now=trie[now][ch],++tag[now];
    }
    ++ed[now];
}
void query(int *ss){
    int now=1,ret=0;
    for(int i=1;i<=len;i++){
        int ch=ss[i];
        if(!trie[now][ch]){
            printf("%d\n",ret);
            return;
        }
        now=trie[now][ch];
        ret+=ed[now];
    }
    printf("%d\n",ret+tag[now]-ed[now]);
}

int main(){
    scanf("%d%d",&m,&n);
    for(int i=1;i<=m;i++){
        scanf("%d",&len);
        for(int j=1;j<=len;j++)scanf("%d",&s[j]);
        insert(s);
    }
    for(int i=1;i<=n;i++){
        scanf("%d",&len);
        for(int j=1;j<=len;j++)scanf("%d",&s[j]);
        query(s);
    }
    return 0;
}

【洛谷P2922】Secret Message