交题链接:First of Her Name
题意:
给出n个人,他们每个人的名字都是之前某个人的名字在最前边加上一个字母得到。比如2号的名字是 A C AC AC,3号在2号前边加一个字母 K K K,这样3号的名字是 K A C KAC KAC。
之后给出k次询问,每次给出一个字符串 T T T,询问名字前缀是 T T T的有几个人。
题解1:
把每个人名字反过来看,所有人的名字就是一个Trie。要求的是以某个T(需要把输入的T给做一次reverse)为后缀的串个数。因此考虑在Trie上建出SAM,然后答案就是T所在自动机节点的后缀树子树大小。
那么由Trie建SAM有若干假算法:如在trie上dfs,然后插入SAM。
正确做法是:在trie上做bfs,这样保证每次插入的点都是第一次出现,而且是按照长度递增的顺序插入,因此复杂度是均摊掉的。只需要每次记录trie上的每个点对应于sam上的每个点,节点的分裂操作并不会改变trie点与sam点的对应关系,因为trie每个点对应的都是“前缀串”,而“前缀串”是他所在节点能够表示的最长串,因此分裂操作只要让原来的老点表示长的那部分,对应关系就不变,可以类比于单串sam的每个前缀所在节点是不变的。
总感觉国内应该每个人都会的trie上sam,结果final上却没人秒这个题。
Code:
// Created by calabash_boy on 19-4-5.
//wf2019 first of her name
//build sam using trie
#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e6+100;
typedef long long ll;
struct Suffix_Automaton{
int nxt[maxn*2][26],fa[maxn*2],l[maxn*2];
int last,cnt;
vector<int> E[maxn*2];
int Num[maxn*2];
Suffix_Automaton(){
clear(); }
void clear(){
last =cnt=1;
fa[1]=l[1]=0;
memset(nxt[1],