【bzoj2555】SubString LCT+后缀自动机
2016-03-01 17:08
309 查看
Description
懒得写背景了,给你一个字符串init,要求你支持两个操作 (1):在当前字符串的后面插入一个字符串 (2):询问字符串s在当前字符串中出现了几次?(作为连续子串) 你必须在线支持这些操作。
Input
第一行一个数Q表示操作个数 第二行一个字符串表示初始字符串init 接下来Q行,每行2个字符串Type,Str Type是ADD的话表示在后面插入字符串。 Type是QUERY的话表示询问某字符串在当前字符串中出现了几次。 为了体现在线操作,你需要维护一个变量mask,初始值为0 读入串Str之后,使用这个过程将之解码成真正询问的串TrueStr。 询问的时候,对TrueStr询问后输出一行答案Result 然后mask = mask xor Result 插入的时候,将TrueStr插到当前字符串后面即可。
HINT:ADD和QUERY操作的字符串都需要解压
Output
Sample Input
2 A QUERY B ADD BBABBBBAAB
Sample Output
0
HINT
40 % 的数据字符串最终长度 <= 20000,询问次数<= 1000,询问总长度<= 10000100 % 的数据字符串最终长度 <= 600000,询问次数<= 10000,询问总长度<= 3000000
新加数据一组–2015.05.20
Source
Ctsc模拟赛By 洁妹顺手复习了一下LCT…细节处理什么的早忘了TAT
因为强制在线,还支持后面插入字符串,所以需要用后缀自动机,要找某个串在其中出现多少次,就是求这个串的right集合大小,也就是parent树的子树大小…
插入一个字符,这个字符在它所处的parent链上对它的祖先每个贡献了1,需要每个祖先加1
然而因为数据加强了,不能暴力修改(实测T掉了…)所以需要把这个点到根节点的权值加1…
因为后缀自动机的建立过程中parent树是不断加边、删边的,所以LCT维护parent树…
细节处理:copy的时候别忘了copyright集合大小,想得到q的在LCT中的权值v需要先pushpath一遍,查询的时候需要得到LCT中的真实值所以要pushpath一遍
这是我学的最复杂的两个数据结构了…
#include<cstdio> #include<cstring> #include<algorithm> #include<iostream> using namespace std; const int SZ = 2000010; const int MAXN = 1200010; namespace LCT{ struct node{ node *ch[2],*f; int sz,sum,v; bool rev; int add; void maintain() { sum = v + ch[0] -> sum + ch[1] -> sum; sz = ch[0] -> sz + 1 + ch[2] -> sz; } void pushdown(); int dir() { return f -> ch[1] == this; } bool isroot() { return f -> ch[0] != this && f -> ch[1] != this;} void setc(node* x,int d) { (ch[d] = x) -> f = this; } }T[SZ],*tree[SZ],*null; int Tcnt = 0; node* newnode(int x) { node *k = T + (Tcnt ++); k -> ch[1] = k -> ch[0] = k -> f = null; k -> sz = 1; k -> sum = k -> v = x; k -> add = k -> rev = 0; return k; } void pushrev(node *p) { if(p == null) return; p -> rev ^= 1; swap(p -> ch[0],p -> ch[1]); } void pushadd(node *p,int add) { if(p == null) return; p -> v += add; p -> sum += add * p -> sz; p -> add += add; } void node :: pushdown() { if(rev) pushrev(ch[0]),pushrev(ch[1]),rev = 0; if(add) pushadd(ch[0],add),pushadd(ch[1],add),add = 0; } node *S[SZ]; int top = 0; void pushpath(node *p) { while(!p -> isroot()) S[++ top] = p,p = p -> f; S[++ top] = p; while(top) S[top --] -> pushdown(); } void rotate(node *p) { node *fa = p -> f; int d = p -> dir(); p -> f = fa -> f; if(!fa -> isroot()) p -> f -> ch[fa -> dir()] = p; fa -> ch[d] = p -> ch[d ^ 1]; if(fa -> ch[d] != null) fa -> ch[d] -> f = fa; p -> setc(fa,d ^ 1); fa -> maintain(); p -> maintain(); } void splay(node *p) { pushpath(p); while(!p -> isroot()) { if(p -> f -> isroot()) rotate(p); else { if(p -> dir() == p -> f -> dir()) rotate(p -> f),rotate(p); else rotate(p),rotate(p); } } p -> maintain(); } void access(node *p) { node *last = null; while(p != null) { splay(p); p -> ch[1] = last; p -> maintain(); last = p; p = p -> f; } } void toroot(node *p) { access(p); splay(p); pushrev(p); } void cut(node *x,node *y) { toroot(x); access(y); splay(y); y -> ch[0] = x -> f = null; } void link(node *x,node *y) { toroot(x); x -> f = y; } void add(node *x,node *y,int d) { toroot(x); access(y); splay(y); pushadd(y,d); } int ask(node *x,node *y) { toroot(x); access(y); splay(y); return y -> sum; } void init() { null = newnode(0); null -> sz = 0; for(int i = 0;i <= MAXN;i ++) tree[i] = newnode(0); } }; namespace SAM{ struct sam_node{ sam_node *ch[5],*par; int val; }T[SZ], *root, *last; LCT :: node* getnode(sam_node *p) { return LCT :: tree[p - T]; } int Tcnt = 0; sam_node* newnode(int x) { sam_node *k = T + (Tcnt ++); k -> val = x; k -> par = 0; memset(k -> ch,0,sizeof(k -> ch)); return k; } void sam_insert(int x) { sam_node *p = last,*np = newnode(last -> val + 1); while(p && !p -> ch[x]) p -> ch[x] = np,p = p -> par; if(!p) { np -> par = root; LCT :: link(getnode(np),getnode(root)); } else { sam_node *q = p -> ch[x]; if(q -> val == p -> val + 1) { np -> par = q; LCT :: link(getnode(np),getnode(q)); } else { sam_node *nq = newnode(p -> val + 1); LCT :: cut(getnode(q),getnode(q -> par)); LCT :: link(getnode(nq),getnode(q -> par)); LCT :: link(getnode(nq),getnode(q)); LCT :: link(getnode(nq),getnode(np)); pushpath(getnode(q)); getnode(nq) -> v = getnode(q) -> v; memcpy(nq -> ch,q -> ch,sizeof(nq -> ch)); nq -> par = q -> par; np -> par = q -> par = nq; while(p && p -> ch[x] == q) p -> ch[x] = nq,p = p -> par; } } LCT :: add(getnode(np),getnode(root),1); last = np; } int ask(char s[]) { int l = strlen(s); sam_node *p = root; for(int i = 0;i < l;i ++) { int c = s[i] - 'A' + 1; if(!p -> ch[c]) return 0; p = p -> ch[c]; } LCT :: pushpath(getnode(p)); return getnode(p) -> v; } void init() { root = newnode(0); last = root; } } void jieya(char s[],int mask) { int l = strlen(s); for(int i = 0;i < l;i ++) { mask = (mask * 131 + i) % l; swap(s[i],s[mask]); } } char s[SZ],opt[233]; int main() { SAM :: init(); LCT :: init(); int n; scanf("%d",&n); scanf("%s",s); int l = strlen(s); for(int i = 0;i < l;i ++) SAM::sam_insert(s[i] - 'A' + 1); int mask = 0,ans = 0; while(n --) { scanf("%s",opt); if(opt[0] == 'Q') { scanf("%s",s); jieya(s,mask); ans = SAM::ask(s); printf("%d\n",ans); mask ^= ans; } else { scanf("%s",s); jieya(s,mask); int l = strlen(s); for(int i = 0;i < l;i ++) SAM::sam_insert(s[i] - 'A' + 1); } } return 0; } /* 5 AAA QUERY A QUERY AA ADD BA QUERY A QUERY AB */
相关文章推荐
- 在数组中交换变量的陷阱
- AIDL学习笔记
- 我的软件工程课目标
- 每周10题 NO.1
- POJ 2560 Freckles(最小生成树-Kruskal)
- 选择图片——笔记
- 静态加载Fragment出错原因
- oracle数据库中数据库名、实例名、数据库域名、全局数据库名、数据库服务名,ORACLE_SID
- java程序员认证考试题库
- 16.3.1-sp_getapplock
- 用MATLAB處理grib2數據
- NIO学习demo
- 道客巴巴
- 整合网上资源 整理的 Alfred 2 的配置教程
- 关于联想键盘,如何去除fn 键 联想官方解决方法
- Linux-0.11内核源代码分析系列:内存管理get_free_page()函数分析
- 安装php扩展模块参数memcache和memcached在php中的应用
- c语言:有10个地区的面积,要求它们按从小到大的顺序排列。(起泡法的应用)
- oracle 迭代查询
- mac 安装Jenkins问题记录