P5212 SubString

题意

给出字符串S和操作次数Q
ADD:往S后继续加一个字符串
QUERY:求给出的字符串在S中出现次数
考虑SAM,插入是O(n)的,查询位置时O(n)的,问题是怎么动态维护出sz[],sz[]其实就是在后缀树上u节点子树中结束节点的个数和。
考虑到要动态加边,删边,求子树和,可以用LCT维护。
每个np(新加节点)将其到根节点的路径上都加上1就行了。查询直接splay(i)查询sum[i]即可
不需要makeroot和split操作,因为根节点一定是1,而且可以直接cut子树

#include <bits/stdc++.h>
#define lc ch[x][0]
#define rc ch[x][1]
#define jh(x, y) (x ^= y, y ^= x, x ^= y)
#define ll long long
using namespace std;
inline void read(int &x) {x = 0; int f = 1; char ch = getchar();while (!(ch >= '0' && ch <= '9')) { if (ch == '-') f = -1; ch = getchar(); }while (ch >= '0' && ch <= '9') { x = (x << 3) + (x << 1) + ch - 48; ch = getchar(); }x *= f;
}
const int N = 6e6 + 10;
int mask, Q, ans;
char s[N];
void Gets(int mask) {scanf("%s", s);for (int j = 0, len = strlen(s); j < len; j++) {mask = (mask * 131 + j) % len;char t = s[j];s[j] = s[mask];s[mask] = t;}
}
struct LCT {int ch[N][2], fa[N], sum[N], tag[N];inline int chk(int x) { return x == ch[fa[x]][1]; }inline int nroot(int x) { return x == ch[fa[x]][chk(x)]; }//pushdown的时候加上tag即可,其他和lct板子一样inline void pushdown(int x) {if (tag[x]) {if (lc) sum[lc] += tag[x], tag[lc] += tag[x];if (rc) sum[rc] += tag[x], tag[rc] += tag[x];tag[x] = 0;}}inline void Rotate(int x) {int y = fa[x], z = fa[y], k = chk(x), w = ch[x][k ^ 1];if (nroot(y)) ch[z][chk(y)] = x;ch[y][k] = w; ch[x][k ^ 1] = y;if (w) fa[w] = y;fa[x] = z; fa[y] = x;}inline void pushall(int x) { if (nroot(x)) pushall(fa[x]); pushdown(x); }inline void splay(int x) {pushall(x);while (nroot(x)) {int y = fa[x];if (nroot(y)) Rotate((chk(x) ^ chk(y)) ? x : y);Rotate(x);}}inline void access(int x) {for (int y = 0; x; x = fa[y = x])splay(x), ch[x][1] = y;}//link操作很简单,因为插入的x节点一定是他的树的根节点,可以直接连inline void link(int x, int y) { fa[x] = y; }//cut可以直接把x的子树全部分离inline void cut(int x) {access(x), splay(x);fa[ch[x][0]] = 0, ch[x][0] = 0;}//update先将要修改的点splay到根上后直接给新节点打上tag加1标记即可inline void update(int x) {access(x); splay(x); tag[x] = sum[x] = 1;}
}lct;
struct SAM {int ch[N][2], mxl[N], pre[N], last, cnt;SAM() { last = cnt = 1; }inline void Extend(int c) {int p = last, np = ++cnt; last = np;mxl[np] = mxl[p] + 1;for (; p && !ch[p][c]; p = pre[p]) ch[p][c] = np;//其实就是在修改pre时在lct,link起来if (!p) { pre[np] = 1; lct.link(np, 1); lct.update(np); return; }int q = ch[p][c];if (mxl[q] == mxl[p] + 1) { pre[np] = q; lct.link(np, q); lct.update(np); return; }int nq = ++cnt;memcpy(ch[nq], ch[q], sizeof(ch[q]));mxl[nq] = mxl[p] + 1; pre[nq] = pre[q]; pre[q] = pre[np] = nq;//在修改pre时,cut掉lct.cut(q); lct.sum[nq] = lct.sum[q];lct.link(q, nq); lct.link(np, nq); lct.link(nq, pre[nq]);lct.update(np);for (; ch[p][c] == q; p = pre[p]) ch[p][c] = nq;}inline void add() {Gets(mask);for (int i = 0, len = strlen(s); i < len; i++) Extend(s[i] - 'A');}inline int query() {Gets(mask);int p = 1;for (int i = 0, len = strlen(s); i < len; i++) {if (!ch[p][s[i] - 'A']) return 0;p = ch[p][s[i] - 'A'];}lct.splay(p);mask ^= lct.sum[p];return lct.sum[p];}
}sam;
char opt[5];
int main() {read(Q);scanf("%s", s + 1);for (int i = 1, len = strlen(s + 1); i <= len; i++) sam.Extend(s[i] - 'A');while (Q--) {scanf("%s", opt);if (opt[0] == 'A') sam.add();else printf("%d\n", sam.query());}return 0;
}

SubString SAM+LCT相关推荐

  1. 2019.03.01 bzoj2555: SubString(sam+lct)

    传送门 题意简述: 要求在线支持两个操作 (1):在当前字符串的后面插入一个字符串 (2):询问字符串s在当前字符串中出现了几次?(作为连续子串) 思路: 考虑用lctlctlct来动态维护samsa ...

  2. 洛谷 - P6292 区间本质不同子串个数(SAM+LCT+线段树)

    题目链接:点击查看 题目大意:给出一个长度为 n 的字符串,再给出 m 次询问,每次询问需要回答区间 [ l , r ] 内有多少个本质不同的字符串 题目分析:首先简化模型,回顾一下如何求解 &quo ...

  3. PKUSC2018训练日程(4.18~5.30)

    (总计:共66题) 4.18~4.25:19题 4.26~5.2:17题 5.3~5.9: 6题 5.10~5.16: 6题 5.17~5.23: 9题 5.24~5.30: 9题 4.18 [BZO ...

  4. 平衡树+LCT全纪录

    平衡树(splay) 平衡数模板 平衡树能干些什么呢? 插入一个数 删除一个数 查询数 x x x的排名(小于x" role="presentation" style=& ...

  5. 其他-私人♂收藏(比赛记录 Mar, 2019)

    OwO 03.03 [USACO19JAN] A. Redistricting 题意:给 \(g\) ,求 \(f(n)\) . \(f(i)=f(j)+[g(i)\ge g(j)],j \in (i ...

  6. 【BZOJ4545】DQS的trie

    Description DQS的自家阳台上种着一棵颗粒饱满.颜色纯正的trie. DQS的trie非常的奇特,它初始有n0个节点,n0-1条边,每条边上有一个字符.并且,它拥有极强的生长力:某个i时刻 ...

  7. BZOJ 5384 有趣的字符串题(区间本质不同回文串数量)

    题意: 多次求区间本质不同回文串数量. 我们知道区间本质不同子串个数是SAM+LCT+BIT. 所以区间本质不同回文串个数就是PAM+SegmentTree+BIT. 为什么可以搏一搏LCT变线段树呢 ...

  8. ZR2019暑期集训游记

    Day2019.7.29: 在鸽了许久后,我终于过来了- 然而课已经上了两天了- Day2019.7.30: 早上很早跟着qt大佬起床了,然而还是没抢到什么好位置- 早饭看起来海星啊,但是为什么感觉人 ...

  9. JSOI 2018 Round 1 游记

    清明时节雨纷纷,路上行人欲断魂. 一年一度的JSOI,已在不觉中来临. 无论是LGM神犇,抑或只是初一蒟蒻,尽在这不大的赛场中相遇--他们无不在用一行行代码,谱写出自己被OI所充实的青春. [以上:伪 ...

最新文章

  1. Mac 从Makefile 编译 Rocksdb 源码的一些注意事项
  2. java理解程序逻辑_使用java理解程序逻辑(12)
  3. VS Code 全部快捷键一览表(巨TM全)
  4. Strange Birthday Party CodeForces - 1471C
  5. leetcode46. 全排列(回溯)
  6. LinkedIn 详细介绍了他们开源的 Kafka Monitor
  7. matlab中符号对象的数据类型是,符号对象(Symbolic Object)的使用
  8. (c语言)输入两个整数a和n,计算下面表达式的值。Sn=a+aa+aaa+aaaa+.....+aa..aa(n个a)
  9. servlet监听器Listener(理论+例子)
  10. 使用C#来手动连接 Access 2007数据库
  11. 单双面打印价格一样吗_正式合同应该打印单面还是双面?
  12. CSDN开博三周年--回首向来萧瑟处,铁马冰河入梦来
  13. 小米笔记本 镜像_小米笔记本Air 13.3 指纹版安装黑苹果 macOS High Sierra 10.13 教程...
  14. 【ATSC】 为什么选择ATSC 3.0
  15. (第十三届蓝桥杯省赛)试题J:砍竹子(优先队列+模拟)
  16. 《胡雪岩》影评10篇
  17. Raspberry Pi OS 2022年09月发布,安装及成功连接。
  18. python连通区域计算长度_连通区域算法小结
  19. tornado源码分析-Application
  20. 撸起袖子加油干努力实现中国梦想PPT模板

热门文章

  1. 问题 C: 网格涂色
  2. 超全总结!详解计算机视觉中的特征点检测:Harris / SIFT / SURF / ORB
  3. DG 主库fial over,强制激活备库解决案例
  4. 利用NSA的MS17-010漏洞利用工具攻击Windows7
  5. 计算机图形学的应用虚拟现实相关,虚拟现实技术中计算机图形学的应用——三维计算机图形.doc...
  6. 台湾评论大陆量子计算机,台湾媒体盛赞大陆工业科研水平 称台湾人对大陆懵懂无知...
  7. 根号6用计算机怎么算,根号6等于多少怎么算
  8. ISO-8601,日期时间格式表示法的国际标准
  9. 贵州计算机教师资格证报名条件,贵州教师资格证报名条件
  10. 前端开发学习笔记(二)JavaScript DOM编程技术(一、二)