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;
}

 

posted @ 2018-09-09 10:00  kafuuchino  阅读(176)  评论(0编辑  收藏  举报