2555: SubString

Time Limit: 30 Sec  Memory Limit: 512 MB
Submit: 2045  Solved: 583
[Submit][Status][Discuss]

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操作的字符串都需要解压


题意:

维护一个串,支持在末尾添加一个字符和询问一个串在其中出现了多少次这两个操作。


出现次数就是走完这个字符串到达的状态的|Right|

然后就变成了动态维护Right集合大小

用LCT来维护Parent Tree,支持区间修改和单点查询即可,加入np的时候Link,需要用nq替换q的时候Cut和Link,进行这些操作时需要更新这个点到根的|Right|集合大小

Link和Cut写的灵活一点   要处理到根的路径哦

这里的LCT维护的是有向树,所以不用MakeRoot,连rev都省了

注意:

1.看明白人家mask是传的参数....并且第一个串不用

2.查询时如果走不了转移边就说明没有出现过!!!然后因为打了标记需要先下传标记在用t[u].w

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <map>
using namespace std;
#define lc t[x].ch[0]
#define rc t[x].ch[1]
#define pa t[x].fa
const int N=2e6+5;
inline int read(){char c=getchar();int x=0,f=1;while(c<'0'||c>'9'){if(c=='-')f=-1; c=getchar();}while(c>='0'&&c<='9'){x=x*10+c-'0'; c=getchar();}return x*f;
}struct Node{int ch[2],fa,w,add;
}t[N];
inline int isR(int x){return t[pa].ch[0]!=x&&t[pa].ch[1]!=x;}
inline int wh(int x){return t[pa].ch[1]==x;}
inline void paint(int x,int d){t[x].add+=d;t[x].w+=d;}
inline void pushDown(int x){if(t[x].add){paint(lc,t[x].add);paint(rc,t[x].add);t[x].add=0;}
}
inline void rotate(int x){int f=t[x].fa,g=t[f].fa,c=wh(x);if(!isR(f)) t[g].ch[wh(f)]=x;t[x].fa=g;t[f].ch[c]=t[x].ch[c^1];t[t[f].ch[c]].fa=f;t[x].ch[c^1]=f;t[f].fa=x;
}
inline void pd(int x){if(!isR(x)) pd(t[x].fa);pushDown(x);
}
inline void splay(int x){pd(x);for(;!isR(x);rotate(x))if(!isR(pa)) rotate(wh(x)==wh(pa)?pa:x);
}
inline void Access(int x){for(int y=0;x;y=x,x=pa)splay(x),rc=y;
}
inline void Link(int x,int y){t[x].fa=y;Access(y);splay(y);paint(y,t[x].w);
}
inline void Cut(int x){Access(x);splay(x);paint(lc,-t[x].w);t[lc].fa=0;lc=0;//update(y);
}
inline void SetW(int x,int v){t[x].w=v;}
inline int GetW(int x){return t[x].w;}int n,Q;
char s[N],op[20];
int mask;
void Decode(char s[],int mask){for(int j=0;j<n;j++){mask=(mask*131+j)%n;swap(s[j],s[mask]);}
}struct SAM{struct State{int ch[26],val,par;}t[N];int sz,root,last;inline int nw(int _){t[++sz].val=_;return sz;}inline void iniSAM(){sz=0;root=last=nw(0);}void extend(int c){int p=last,np=nw(t[p].val+1); SetW(np,1);while(p&&!t[p].ch[c]) t[p].ch[c]=np,p=t[p].par;if(!p) t[np].par=root, Link(np,root);else{int q=t[p].ch[c];if(t[q].val==t[p].val+1) t[np].par=q, Link(np,q);else{int nq=nw(t[p].val+1);memcpy(t[nq].ch,t[q].ch,sizeof(t[q].ch));t[nq].par=t[q].par;    Link(nq,t[q].par);t[q].par=t[np].par=nq; Cut(q);Link(q,nq);Link(np,nq);while(p&&t[p].ch[c]==q) t[p].ch[c]=nq,p=t[p].par;}}last=np;}int Query(){int u=root;for(int i=0;i<n;i++){int c=s[i]-'A';if(t[u].ch[c]) u=t[u].ch[c];else return 0;}pd(u);//!!return GetW(u);}void Insert(){for(int i=0;i<n;i++) extend(s[i]-'A');}
}sam;
int main(){freopen("in","r",stdin);sam.iniSAM();scanf("%d%s",&Q,s);n=strlen(s);sam.Insert();while(Q--){scanf("%s%s",op,s);n=strlen(s);Decode(s,mask);if(op[0]=='A') sam.Insert();else{int _=sam.Query();printf("%d\n",_);mask^=_;}//puts(s);
    }
}

BZOJ 2555: SubString [后缀自动机 LCT]相关推荐

  1. BZOJ.2555.SubString(后缀自动机 LCT)

    题目链接 \(Description\) 给你一个字符串init,要求支持两个操作: (1)在当前字符串的后面插入一个字符串s (2)询问字符串s在当前字符串中出现了几次(作为连续子串) 强制在线. ...

  2. HDU多校4 - 6988 Display Substring(后缀自动机+二分)

    题目链接:点击查看 题目大意:给出一个长度为 nnn 的字符串 sss,每个字母都有一个权值,现在要求所有本质不同子串中权值和第 kkk 大的权值 题目分析:如果没有本质不同,那有一个很简单的二分套二 ...

  3. BZOJ 3238 差异 [后缀自动机]

    题目 一个长度为n的字符串S,令TiT_i表示它从第i个字符开始的后缀.求 ∑1≤i<j≤nlen(Ti)+len(Tj)−2∗lcp(Ti,Tj) \sum_{1\le i 其中len(a)表 ...

  4. 【BZOJ4545】DQS的trie 后缀自动机+LCT

    [BZOJ4545]DQS的trie Description DQS的自家阳台上种着一棵颗粒饱满.颜色纯正的trie. DQS的trie非常的奇特,它初始有n0个节点,n0-1条边,每条边上有一个字符 ...

  5. [BZOJ 2555] SubString

    Substring 题意 题面 给定一个初始字符串, 要求支持在这个字符串后添加字符串/查询某个字符串作为子串的出现次数. 强制在线. 长度 \(\le600000\),询问次数 \(\le10000 ...

  6. [bzoj 2555]Substring

    传送门 Description 给你一个字符串\(init\),要求你支持两个操作 (1):在当前字符串的后面插入一个字符串 (2):询问字符串s在当前字符串中出现了几次?(作为连续子串) 你必须在线 ...

  7. 「雅礼集训 2017 Day7」事情的相似度(后缀自动机+LCT+树状数组)

    description 点击查看题目内容 solution Step1 无脑建SAMSAMSAM 两个前缀的最长公共后缀就是parent−treeparent-treeparent−tree上两点的l ...

  8. SPOJ - LCS Longest Common Substring(后缀自动机)

    题目链接:点击查看 题目大意:给出两个字符串,求出其最长公共子串的长度 题目分析:可以对第一个字符串建立SAM,然后令第二个字符串在建好的SAM上跑就好了,如果遇到不能跑的点,就往上折返直到找到可以继 ...

  9. UOJ #395 BZOJ 5417 Luogu P4770 [NOI2018]你的名字 (后缀自动机、线段树合并)

    NOI2019考前做NOI2018题.. 题目链接: (bzoj) https://www.lydsy.com/JudgeOnline/problem.php?id=5417 (luogu) http ...

最新文章

  1. git操作手册_基本的Git手册
  2. 【怎样写代码】参数化类型 -- 泛型(五):泛型类
  3. win10安装配置gcc编译环境
  4. Kruskal HDOJ 1233 还是畅通工程
  5. 全球首个AI设计药物诞生,淘宝新增垃圾识别功能……
  6. 2016012075 谢月月 散列函数的应用及其安全性
  7. 【推荐】在R中无缝集成Github云端代码托管
  8. 网页内嵌多媒体 IE,Mozilla、Firefox、NetScape、Opera
  9. 盖世无双之国产数据库风云榜-2022年02月
  10. 理科生的人生感悟-02-别忘了别人的痛苦 - 丰收之歌和围墙外的稻田
  11. Qt Moc 文件解析
  12. PHP快速输出26大小写字母
  13. 记账本软件的用例描述
  14. 北京8成楼盘降价促销 房价已下跌10%-15%
  15. Google Filament 源码学习(二):三方库分类总结
  16. 怎么写安卓手机脚本_拉结尔手游攻略,云手机全自动挂机刷副本及装备
  17. 刚刚,马斯克宣布重磅消息!一切来得那么快!
  18. 微信小程序地址选择组件(仿拼多多App版地址选择)
  19. 改进YOLOv5系列:首发结合最新efficient Layer Aggregation Networks结构,高效的聚合网络设计,提升性能
  20. 高等数学(函数的极限与连续性)

热门文章

  1. Java开发中的基本数据类型有哪些?
  2. Java基础:BufferedWriter和PushbackReader
  3. cloudstack: 使用服务器No usage server process running
  4. 重新认识C#: 玩转指针
  5. 犹太教、基督教和伊斯兰教的简单关系
  6. phalapi-进阶篇3(自动加载和拦截器)
  7. AudioToolbox音效播放
  8. DR、BDR和DROther的关系之通俗演绎
  9. java 短连接+MD5加密短链接
  10. 【EOS】2.4 EOS数据存储