【洛谷P2922】Secret Message
阿新 • • 發佈:2019-05-07
順序 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