1、先不考虑交换问题, 只考虑查询。一般公共前缀问题就往字典树上去想,那么先将所有字符串转化为字典树上的东西,那么公共前缀为k,我们先找到这个点,x,那么发现所有符合条件的都在x的子树下面,那么现在可以把整个树做一个dfs序,就可以快速的表示x的子树范围,那么x的范围设置为dfn[x] , ed[x] ,一个进入dfs序,一个退出dfs序,
2、现在我们就是要在[dfn[x] , ed[x]] 之前查找[L , R ] 的个数,现在这个求解就直接容斥一下(简单的相加减) , [dfn[x] , r] - [dfn[x] + sz[x] - 1 , r] - ([dfn[x] , l - 1] - [dfn[x] + sz[x] - 1 , l - 1])
3、 那么我们现在就是求解[1 , dfn[x]] 里面有多少[1 , r]
4、那么发现对于某一个dfn[x]而言,只需要比它小的dfx[y] , 对于某个r来说,只需要比它小的r'
5、我们可以先把所有的字符串的所有dfn和编号id保存一下,那么可以用二维偏序来求出结果,只要看比dfn[x]小的有多少[1 , r],经典二维偏序问题,排序加树状数组可以解决
6、再考率交换问题,它会交换两个字符串,但是在上面的问题抽像出来之后,只关注dfs序和它的标号,标号肯定是不变的,那么只需要交换标号。但是交换肯定付出代价,因为在第5步,我们插入了所有的字符串,交换的话肯定需要将交换之前的贡献删除,将交换之后的贡献插入。
7、问题出现了,那么我们这个怎么插入,直接插入的话如何保证这个交换只会对后面的查询有影响,而不对前面的查询有影响。我们发现这个是否对前后有影响是因为时间原因,查询和修改的时间关系决定的。那么我们就再引入一维,时间戳t。那么第6步的基础上加一维时间t。经典三维偏序问题。
8、现在就是要求出来,对于某个[t , dfn[x] , r] ,有多少[t' , dfn[x]' , r'] , 满足 t' <= t && dfn[x]' <= dfn[x] , r' <= r
/*
*@author spnooyseed
*/
#pragma GCC optimize("Ofast","unroll-loops","omit-frame-pointer","inline")
#pragma GCC optimize(3 , "Ofast" , "inline")
#pragma GCC optimize("Ofast")
#pragma GCC target("avx,avx2,fma")
#pragma GCC optimization("unroll-loops")
#include
#include
#include
#include
#include
#include