题目链接在这里洛谷/LOJ 题目大意 有一个串\(S\),每次询问给你一个串\(T\),两个数\(L\)和\(R\),问你\(T\)有多少个本质不同的子串不是\(S[L,R]\)的子串 SOLUTION 如果你做过生成魔咒和CF1037H,就会做这道题了 有两个坑点: 1.线段树合并时必须每次都新建结点,因为两颗树都得保留 2.每次失配时必须先尝试减小已经匹配的长度,无法继续减少时再跳\(suflink\) 我的大常数代码 #include <algorithm> #include <i…
考虑l=1,r=n的68分,对S和T建SAM,对T的SAM上的每个节点,计算它能给答案带来多少贡献. T上节点x代表的本质不同的子串数为mx[x]-mx[fa[x]],然后需要去掉所代表子串与S的最长公共子串的长度. 从1到length(T)扫一遍,SAM基本操作求出每个前缀与S的最长公共子串. 答案为$\sum_{i=1}^{cnt}max(0,mx[x]-max(mx[fa[x]],len[tag[x]]))$,其中tag[x]是x所代表的子串在T中的第一个出现位置,len[i]为T的前缀i…
题意 题目链接 Sol 首先不难想到一个dp,设\(f[i][j]\)表示\(i\)的子树内选择的最小值至少为\(j\)的最大个数 转移的时候维护一个后缀\(mx\)然后直接加 因为后缀max是单调不升的,那么我们可以维护他的差分数组(两个差分数组相加再求和 与 对两个原数组直接求和是一样的) 向上合并的过程中对\(a[x]\)处\(+1\),再找到\(a[x]\)之前为\(1\)的位置\(-1\)即可 (怎么感觉暴力区间加也可以qwq) 复杂度\(O(nlogn)\) // luogu-jud…
传送门 给出n个带点权的点,支持连边和查询连通块第k大. 这个貌似就是一道线段树合并的裸板啊... 代码: #include<bits/stdc++.h> #define N 100005 using namespace std; inline int read(){ int ans=0; char ch=getchar(); while(!isdigit(ch))ch=getchar(); while(isdigit(ch))ans=(ans<<3)+(ans<<1)…
[BZOJ5417][NOI2018]你的名字(线段树,后缀自动机) 题面 BZOJ 洛谷 题解 首先考虑\(l=1,r=|S|\)的做法,对于每次询问的\(T\)串,暴力在\(S\)串的\(SAM\)上跑,对于每个点记录其被匹配的最大长度,然后把每个被匹配到的点以及它到\(parent\)树根节点的所有节点全部计算一下能够被匹配的最大长度,最后计算一下有多少个串在\(S\)中出现过.拿总方案减去不合法就行了. 然后现在\(l,r\)任意,那么首先线段树合并求出所有的\(endpos\). 一样…
传送门 思路 按照套路,直接上后缀自动机. 部分分:\(l=1,r=|S|\) 首先把\(S\)和\(T\)的后缀自动机都建出来. 考虑枚举\(T\)中的右端点\(r\),查询以\(r\)结尾的串最长可以往左延伸多长,使得它仍然是\(S\)的子串.记该长度为\(lim_r\). \(lim_r\)可以在\(SAM_S\)中瞎跳跳出来. 那么答案即为 \[ \sum_{i=2}^{cnt} \max(0,len_i-\max(len_{fa_i},lim_{pos_i})) \] 其中\(i\)是…
Description Hint Solution 不妨先讨论一下无区间限制的做法. 首先"子串"可以理解为"前缀的后缀",因此我们定义一个 \(\lim(i)\),表示 \(T\) 的一个前缀 \(T[1\cdots i]\) 中,选取一个最长后缀,使得这个后缀在 \(S\) 中出现过.\(\lim(i)\) 就是这个最长后缀的长度. 其实与朴素的 SAM 求最长公共子串有点相似,这里主要是求 本质不同的公共子串的个数. 我们对 \(S\) 建 SAM,然后把 \…
对S建SAM,拿着T在上面跑 跑的时候不仅无法转移要跳parent,转移过去不在范围内也要跳parent(注意因为范围和长度有关,跳的时候应该把长度一点一点地缩) 这样就能得到对于T的每个前缀,它最长的不合法的后缀的长度ill[i] 得到他要去重,以后可以再对T建SAM,然后对于每个节点,$ans+=max(0,len[i]-max(len[fa[i]],ill[pos[i]]))$,其中pos[i]是它的right集合中随便一个位置(因为每个位置的小于len的ill都一样) 那么怎么判在不在范…
原文链接https://www.cnblogs.com/zhouzhendong/p/LuoguP4482.html 题意 给定一个字符串 S,有 q 次询问,每次给定两个数 L,R ,求 S[L...R] 的最长前后缀. $$q,|S|\leq 2 \times 10 ^ 5$$ 题解 真是一道有趣的字符串题. 首先我们给 S 建出 SAM ,并用线段树合并预处理出每一个节点的 Right 集合. 我们要做的是找到最大的 $p$ 满足 $p<R, S[L...p] = S[R-p+L...R]…
原文链接https://www.cnblogs.com/zhouzhendong/p/UOJ395.html 题解 记得同步赛的时候这题我爆0了,最暴力的暴力都没调出来. 首先我们看看 68 分怎么做 ——求两个串的本质不同的公共子串个数. 它是一个模板题,然而我当时并不会,甚至连SAM都忘了怎么写QAQ. 再简化一下:如何求一个串的本质不同的子串个数. 给串建一个SAM,把所有节点代表的字符串个数(也就是 Max(x) - Max(fa(x)) 加起来就好了. 回到上一个问题. 假设这两个串分…
正题 题目链接:https://www.luogu.com.cn/problem/P4770 题目大意 给出一个长度为\(n\)的字符串\(S\).\(q\)次询问给出一个串\(T\)和一个区间\([L,R]\),求\(T\)有多少个本质不同的子串不是\(S_{L\sim R}\)的子串. \(1\leq n\leq 5\times 10^5,1\leq Q\le 10^5,\sum|T|\leq 10^6\) 解题思路 因为给了很多\(L=1,R=n\)的部分分所以应该是提示我们先从这个方面考…
Codeforces 题面传送门 & 洛谷题面传送门 SAM hot tea %%%%%%% 首先我们显然可以将所有能够得到的字符串分成六类:\(\varnothing,\text{*},s,\text{*}s,s\text{*},s\text{*}t\),其中 \(s,t\) 分别代表某个非空字符串,\(\text{*}\) 则代表题目中的星号,显然前两种情况的贡献都是 \(1\),算出后几种情况的答案后直接加 \(2\) 即可,第三种情况也异常简单,相当于求 \(s\) 中本质不同的子串个数…
又是一道\(SAM\)维护\(endpos\)集合的题,我直接把CF700E的板子粘过来了QwQ 思路 如果我们有\([l,r]\)对应的\(SAM\),只需要在上面贪心就可以了.因为要求的是字典序比\(T\)大且最小的子串,我们从前到后让尽可能多的位相等,如果再也无法相等了就从后往前找一位变大. 但是每次询问会给我们一个可行区间\([l,r]\),而我们又显然不能直接把对应区间的\(SAM\)建出来,否则复杂度会\(GG\). 仔细想一下,其实我们并不需要知道\([l,r]\)区间对应的\(S…
原文链接https://www.cnblogs.com/zhouzhendong/p/CF700E.html 题解 首先建个SAM. 一个结论:对于parent树上任意一个点x,以及它所代表的子树内任意一个点y,设节点y代表的最长串为S,设节点x代表的串为T1,T2,T3,...,设 F(S,T) 表示串T在S中的出现次数,则 F(S,T1) = F(S,T2) = F(S,T3) = ... 证明:假设串 Ta 和 Tb 在 S 中的出现次数不同,且 |Ta|+1=|Tb| 则必然存在一个位置…
题意:给你一个子串,m次询问,每次给你abcd,问你子串sa-b的所有子串和子串sc-d的最长公共前缀是多长 题解:首先要求两个子串的最长公共前缀就是把反过来插入变成最长公共后缀,两个节点在parent树上的lca就是最长公共后缀.找到某个子串就是在parent树上倍增 我们先二分答案,问题就变成了子串sx-y的所有子串中是否包含子串p,我们先倍增找到子串p,然后查询p在parent树上的子树是否包含子串sx-y的子串(parent树上的子树就是所有以p作为后缀的子串,如果sx-y的子串包含p,…
传送门 题意:给一个字符串SSS. 有mmm次询问,每次给四个参数a,b,c,da,b,c,da,b,c,d,问s[a...b]s[a...b]s[a...b]的所有子串和s[x...y]s[x...y]s[x...y]的最长公共前缀是多少. 思路:先翻转字符串转化为求最长公共后缀. 设现在求s[a...b]s[a...b]s[a...b]的所有子串和s[x...y]s[x...y]s[x...y]的最长公共后缀是多少. 然后二分答案,设最长公共后缀为s[y−mid+1...y]s[y-mid+…
Description 给你一个字符串,如果一个串包含两个可有交集的相同子串,那么这个串的价值就是子串的价值+1.问你给定字符串的最大价值子串的价值. Input 第一行读入字符串长度$n$,第二行是字符串. Output 一行答案. Sample Input1 3abc Sample Output1 1 Sample Input2 5ddddd Sample Output2 5 Sample Input3 11abracadabra Sample Output3 3 Solution 首先把后…
题意:给定字符串S:  Q次询问,每次询问给出(L,R,T),让你在S[L,R]里面找一个字典序最小的子串,其字典序比T大. 没有则输出-1: 思路:比T字典序大,而且要求字典最小,显然就是在T的尾巴加一个很小的字符,如果不存在,则依次删去尾巴,直到“存在”. 而“存在”是指,前缀lim+一个字符‘x’后存在于[L+lim,R]中, 所以我们需要预处理出所有点的endpos,这个用线段树合并就可以了. 注意这里是每一个节点都要记录,所以和普通的启发式合并不太一样,这里需要每次新开一个节点. #i…
RemoteJudge 又是一道用线段树合并来维护\(endpos\)的题,还有一道见我的博客CF666E 思路 先把\(SAM\)建出来 如果两个相邻的串\(s_i\)和\(s_{i+1}\)要满足\(s_i\)在\(s_{i+1}\)中至少出现了两次,那么\(s_i\)显然是\(s_{i+1}\)对应的结点在\(parent\ tree\)上的祖先,那么我们可以在\(parent\ tree\)上树形dp来得出答案 转移自顶向下进行,\(s_i\)在\(s_{i+1}\)中至少出现了两次意味…
RemoteJudge 题目大意 给你一个串\(S\)以及一个字符串数组\(T[1...m]\),\(q\)次询问,每次问\(S\)的子串\(S[p_l...p_r]\)在\(T[l...r]\)中的哪个串里的出现次数最多,并输出出现次数. 如有多解输出最靠前的那一个. 思路 第一次见到在\(parent tree\)上线段树合并的题,感觉好妙 先对\(T\)建一个广义后缀自动机,考虑对\(SAM\)上的每一个结点建一颗线段树,值域为\([1,m]\),维护出现次数最多的串的位置和次数.又因为\…
Description 给出一个字符串 \(S\). 给出 \(Q\) 个操作,给出 \(L, R, T\),求字典序最小的 \(S_1\),使得 \(S^\prime\) 为\(S[L..R]\) 的子串,且 \(S^\prime\) 的字典序严格大于 \(T\).输出这个 \(S^\prime\) ,如果无解输出 -1. Hint \(1\le |S|\le 10^5\) \(1\le Q\le 2\times 10^5\) \(1\le L\le R\le |S|\) \(1\le \su…
正题 题目链接:https://www.luogu.com.cn/problem/CF666E 解题思路 给出一个串\(S\)和\(n\)个串\(T_i\).\(m\)次询问\(S_{a\sim b}\)在\(T_{l\sim r}\)中出现的最多次数并且输出这个串的编号. \(1\leq |s|\leq 5\times 10^5,\sum T_i\leq 5\times 10^4,1\leq m\leq 5\times 10^5\) 解题思路 把\(S\)和\(T\)丢一起跑一个广义\(SAM…
正题 题目链接:https://www.luogu.com.cn/problem/CF204E 题目大意 \(n\)个字符串的一个字符串集合,对于每个字符串求有多少个子串是这个字符串集合中至少\(k\)个字符串的子串. 解题思路 因为对于每个字符串我们需要维护的信息不同,不能累加,所以考虑使用线段树合并. 先将\(n\)个字符串构建出一个广义\(SAM\),然后对于每个节点维护一个该线段树表示该节点属于的字符串.然后在\(parents\)树上从下往上合并,如果属于字符串的数量多余\(k\),那…
正题 题目链接:https://www.luogu.com.cn/problem/CF700E 题目大意 给出一个字符串\(S\),求一个最大的\(k\)使得存在\(k\)个字符串其中\(s_1\)是\(S\)的子串,\(s_{i+1}\)在\(s_i\)中出现了至少\(2\)次. 解题思路 首先我们需要有两个结论 \(s_{i+1}\)一定是\(s_i\)的其中一个后缀.因为如果\(s_{i+1}\)不是\(s_i\)的一个后缀,那么\(s_i\)去掉后面那一部分不会影响匹配数并且更短,也就是…
正题 题目链接:https://www.ybtoj.com.cn/problem/532 题目大意 给出\(n\)个点的一个\(Trie\)树,定义\(S_x\)表示节点\(x\)代表的字符串 求$$max{|LCP(S_x,S_y)|+|LCS(S_x,S_y)|}(x\neq y)$$ (\(LCP/LCS\)分别表示最长公共前/后缀) \(1\leq n\leq 2\times 10^5\) 解题思路 正解好像是树上\(SA\)+线段树合并的做法可是我不会,就写了广义\(SAM\) \(S…
传送门 我有种自己根本没学过SAM的感觉……最后还是抄了老半天的题解…… 首先,对$S$和每一次的$T$都建一个SAM 先考虑一下$l=1,r=\left| S \right|$的情况 设$lim_i$表示字符串$T[1..i]$能在$S$中匹配到的最长后缀(即$T[i-lim_i+1,i]$是$S$的子串且$lim_i$最大)(有可能不存在这个字符那么$lim_i=0$) 这个$lim_i$可以不断地在$S$的后缀自动机上跳来求出.当无法向下匹配时,一直跳parent树直到可以匹配为止 我们假…
To 洛谷.2982 慢下来Slowing down 题目描述 Every day each of Farmer John's N (1 <= N <= 100,000) cows conveniently numbered 1..N move from the barn to her private pasture. The pastures are organized as a tree, with the barn being on pasture 1. Exactly N-1 cow…
题面 Bzoj 洛谷 题解 考虑用并查集维护图的连通性,接着用线段树分治对每个修改进行分治. 具体来说,就是用一个时间轴表示图的状态,用线段树维护,对于一条边,我们判断如果他的存在时间正好在这个区间内,那就把它用并查集并起来.最后对于一个询问,直接用并查集找就好了. 但是因为有撤销操作,所以在并查集合并的时候,我们将需要合并的两个点放进栈中,最后栈序撤销,所以只能考虑按秩合并而不能路径压缩. #include <map> #include <vector> #include <…
二分mid,然后用1~mid的操作在差分序列上加减,最后把差分序列前缀和起来,看是否有有超过初始r值的 #include<iostream> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; const int N=1e6,INF=1e9; long long n,m,a[N],d[N],x[N],y[N],s[N]; int read() { int r=…
题目: 洛谷4219 分析: 很明显,查询的是删掉某条边后两端点所在连通块大小的乘积. 有加边和删边,想到LCT.但是我不会用LCT查连通块大小啊.果断弃了 有加边和删边,还跟连通性有关,于是开始yy线段树分治做法(不知道线段树分治?推荐一个伪模板题BZOJ4025二分图事实上这个链接是指向我的博客的).把每次操作(加边或查询)看做一个时刻,一条边存在的区间就是它加入后没有被查询的时间区间的并.于是用可撤销并查集维护一下连通块大小即可. 代码: #include <cstdio> #inclu…