伸展树,LCP(uva,11996)

讲道理,基于哈希值的字符串算法真的很不错。因为unsigned long long高达1e19,而算法竞赛中字符串长度不可能大于1e6,毕竟如果再大,那就连经典字符串算法都无法在短时间求得结果了O(nlongn)。所以重复的概率为1e6*1e6/1e19=1e-7,即只有0.00001%的概率会重复。

在本题中HASH值取3是可以的,而2是不可以的。因为2是unsigned long long最大值的因数(unsigned long long自然溢出相当于对2^64取模,或者把HASH取2理解为左移一位的意思),而3不是。

一开始自己维护hash还用什么快速幂,其实一开始先预处理出来就OK了,这就是经验不足了。

自己最开始的想法还更糟糕呢,竟然想到每次问问题时才来打表。因为自己可能觉得树上维护hash值太难了吧。。只能说明自己其实对基于HASH值得LCP算法不理解(一开始觉得概率算法不靠谱所以只是看了一遍,所用总想着用经典的字符串算法,但是事实上基于HASH的LCP太棒了。),所以不知道该如何应用递推式,所以才觉得难,事实上等自己理解了后也就不会觉得那么难了。至于其他的操作就相对简单了,毕竟上一题就是这些啊。

然后一些技巧吧,用中序遍历的话反转就很简单啦,交换左右子树并留下延迟标记,在需要进入下一层时才下方延迟标记并更新子树。同时维护正反两个hash值在反转的时候也只用swap一下而不是重新计算。求子串的hash值也十分巧妙,竟然是先将子串split出来读取hash值后再merge回去。毕竟没有别的更好的办法了,因为伸展树的形态是不确定的,从而导致你想要的子串很可能不是某棵子树,你想要的hash值甚至还没算出来呢,一定要在split的过程中,才能顺带算出来,再说split时间复杂度又不高才O(logn)。是longn而不是nlogn呀,真的很快了。


代码

#include<bits/stdc++.h>
#define maxn 200010
#define MAXN 400010
using namespace std;
typedef unsigned long long ull;
const ull HASH = 2;

ull mp[MAXN];

struct Node
{
    Node* ch[2];
    int v,s,r;
    unsigned long long
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值