ICPC World Final 2019 G First of Her Name :广义SAM / 离线ACAM / 树上SA

交题链接: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],
  • 5
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值