Tire字典树
#include <bits/stdc++.h>
using namespace std;
const int N = 2e4+10;
int s[N][26];
int cnt[N];
int idx;
void insert(string str)
{
int p = 0;
for(int i = 0; str[i]; i++)
{
int u = str[i] - 'a';
if(!s[p][u]) s[p][u] = ++idx;//s[p][u] 记录下一位的位置,写++idx!
p = s[p][u];
}
cnt[p]++;
}
int query(string str)
{
int p = 0;
for(int i = 0; str[i]; i++)
{
int u = str[i] - 'a';
if(!s[p][u]) return 0;
p = s[p][u];
}
return cnt[p];
}
int main()
{
int n;
cin>>n;
while(n -- )
{
char c;
string str;
cin>>c>>str;
if(c == 'I') insert(str);
else cout<<query(str)<<endl;
}
return 0;
}
作业题:
P2922 [USACO08DEC]Secret Message G
吐槽:这破题,我写了一下午QAQ。
题目类型:Tire
注意点:主体是模板;
不同的字符串的计数位置与意义;
个数计算,注意重复情况。
#include<bits/stdc++.h>
using namespace std;
const int N = 5e6+10;
int s[N][3];
int cnt2[N], cnt1[N];
int str[N];
int idx;
void insertS(int str[], int len)
{
int p = 0;
for(int i = 0; i< len; i++)
{
if(!s[p][str[i]]) s[p][str[i]] = ++idx;
p = s[p][str[i]];
cnt1[p]++;
}
cnt2[p] ++;
}
int query(int str[], int len)
{
int p = 0;
int cot = 0;
for(int i = 0; i<len; i++)
{
//cout<<s[p][str[i]]<<'*';
// cout<<"cot22:"<<cnt2[p]<<"cot11"<<cnt1[p]<<endl;
if(!s[p][str[i]]) return cot;
p = s[p][str[i]];
cot += cnt2[p];//把所有以p为终点的字符串的个数相加
}
//cout<<"cot:; "<<cot<<' '<<"cot22:"<<cnt2[p]<<"cot11"<<cnt1[p]<<endl;
return cot + cnt1[p] - cnt2[p];//why to cutcnt2[p]?因为cnt1[i]是所有经过这个点的字符串,同时也包含了以这个点为终点的字符串,上面这个点也加了一遍,避免重复要删掉!!!
/*cot 在计算前缀字符串长度小于等于查询字符串的情况;cnt1[p]是在计算前缀字符串等于查询字符串的情况*/
}
int main()
{
int n , m;
cin>>n>>m;
for(int i = 1; i<=n; i++)
{
int len;
cin>>len;
for(int j = 0; j<len; j++) cin>>str[j];
insertS(str, len);
}
for(int i = 1; i<=m; i++)
{
int len;
cin>>len;
for(int j = 0; j<len; j++) cin>>str[j];
cout<<query(str, len)<<endl;
}
return 0;
}