P2922 [USACO08DEC]秘密消息Secret Message
P2922 [USACO08DEC]秘密消息Secret Message
Trie
Trie典型统计题
在这题中,我们不是单纯的统计一个串是否是另一个串的前缀,而要统计数量。
在这里,我们引入一个tot标记,表示有多少串包含这个节点(不累计串的结尾)。
当询问的串在路径上的u点时,加上的是a[ u ].end,表示有多少串是询问串的前缀
当询问的串走到树外时,停止统计,表示已经找不到符合前缀条件的串了
当询问的串在树内u点结束时,加上的是a[ u ].tot,表示询问串是多少个串的前缀
end.
#include<iostream> #include<cstdio> #include<cstring> #include<cctype> using namespace std; inline int Int(){ char c=getchar(); int x=0; while(!isdigit(c)) c=getchar(); while(isdigit(c)) x=(x<<3)+(x<<1)+(c^48),c=getchar(); return x; } struct data{ int nxt[2],tot,end; }a[500002]; int n,m,ans,cnt; inline void insert(){ //普通的向Trie内插入单词操作 int u=0,len; len=Int(); for(int i=0;i<len;++i){ int p=Int(); if(!a[u].nxt[p]) a[u].nxt[p]=++cnt; ++a[u].tot; //tot标记 u=a[u].nxt[p]; }++a[u].end; //end不能tot重复 } inline void query(){ int u=0,len; len=Int(); bool useless=0; ans=0; for(int i=0;i<len;++i){ int p=Int(); if(!a[u].nxt[p]||useless) {useless=1; continue;} //跑到树外就不需要统计了 u=a[u].nxt[p]; ans+=a[u].end; } if(!useless) ans+=a[u].tot; //整个串都在树内就加上tot printf("%d\n",ans); } int main(){ m=Int(); n=Int(); for(int i=1;i<=m;++i) insert(); for(int i=1;i<=n;++i) query(); return 0; }