Description

懒得写背景了,给你一个字符串init,要求你支持两个操作
(1):在当前字符串的后面插入一个字符串
(2):询问字符串s在当前字符串中出现了几次?(作为连续子串)
你必须在线支持这些操作。

Input

第一行一个数Q表示操作个数
第二行一个字符串表示初始字符串init
接下来Q行,每行2个字符串Type,Str
Type是ADD的话表示在后面插入字符串。
Type是QUERY的话表示询问某字符串在当前字符串中出现了几次。
为了体现在线操作,你需要维护一个变量mask,初始值为0 

读入串Str之后,使用这个过程将之解码成真正询问的串TrueStr。
询问的时候,对TrueStr询问后输出一行答案Result
然后mask=maskxorResult
插入的时候,将TrueStr插到当前字符串后面即可。
HINT:ADD和QUERY操作的字符串都需要解压
长度 <= 600000,询问次数<= 10000,询问总长度<= 3000000
新加数据一组--2015.05.20

Output

Sample Input

2
A
QUERY B
ADD BBABBBBAAB

Sample Output

0

Solution

可以发现这个题如果不是多组询问的话,就是求SAM的right集合的大小的裸题
不过一边插入一边询问很显然是无法像原来一样等全部字符都插入后再排序求right集合大小的
不过根据right集合的定义,其实我们可以发现一个点的right集合大小就是子树的np节点的个数
这玩意儿只需要用LCT维护子树权值和就好了

Code

  1 #include<iostream>
  2 #include<cstring>
  3 #include<cstdio>
  4 #define N (1200000+1000)
  5 using namespace std;
  6
  7 int Father[N],Son[N][2],Size[N],Si[N],Rev[N],R[N],T,mask;
  8 char s[N],opt[10];
  9
 10 int Get(int x){return Son[Father[x]][1]==x;}
 11 int Is_root(int x){return Son[Father[x]][0]!=x && Son[Father[x]][1]!=x;}
 12 void Update(int x){Size[x]=Si[x]+Size[Son[x][0]]+Size[Son[x][1]]+R[x];}
 13
 14 void Pushdown(int x)
 15 {
 16     if (x && Rev[x])
 17     {
 18         if (Son[x][0]) Rev[Son[x][0]]^=1;
 19         if (Son[x][1]) Rev[Son[x][1]]^=1;
 20         swap(Son[x][0],Son[x][1]);
 21         Rev[x]=0;
 22     }
 23 }
 24
 25 void Rotate(int x)
 26 {
 27     int wh=Get(x);
 28     int fa=Father[x],fafa=Father[fa];
 29     if (!Is_root(fa)) Son[fafa][Son[fafa][1]==fa]=x;
 30     Son[fa][wh]=Son[x][wh^1]; Father[fa]=x;
 31     Son[x][wh^1]=fa; Father[x]=fafa;
 32     if (Son[fa][wh]) Father[Son[fa][wh]]=fa;
 33     Update(fa); Update(x);
 34 }
 35
 36 void Push(int x){if (!Is_root(x)) Push(Father[x]); Pushdown(x);}
 37 void Splay(int x)
 38 {
 39     Push(x);
 40     for (int fa; !Is_root(x); Rotate(x))
 41         if (!Is_root(fa=Father[x]))
 42             Rotate(Get(fa)==Get(x)?fa:x);
 43 }
 44
 45 void Access(int x)
 46 {
 47     for (int y=0; x; y=x,x=Father[x])
 48     {
 49         Splay(x);
 50         Si[x]+=Size[Son[x][1]]; Si[x]-=Size[y];
 51         Son[x][1]=y; Update(x);
 52     }
 53 }
 54
 55 void Make_root(int x){Access(x); Splay(x); Rev[x]^=1;}
 56 int Find_root(int x){Access(x); Splay(x); while (Son[x][0]) x=Son[x][0]; return x;}
 57 void Link(int x,int y){Make_root(x); Make_root(y); Father[x]=y; Si[y]+=Size[x]; Update(y);}
 58 void Cut(int x,int y){Make_root(x); Access(y); Splay(y); Son[y][0]=Father[x]=0; Update(y);}
 59
 60 struct SAM
 61 {
 62     int fa[N],son[N][28],step[N];
 63     int p,q,np,nq,last,cnt;
 64     SAM(){last=++cnt;}
 65
 66     void Insert(int x)
 67     {
 68         p=last; np=last=++cnt; step[np]=step[p]+1; R[np]=1;
 69         while (p && !son[p][x]) son[p][x]=np,p=fa[p];
 70         if (!p) fa[np]=1,Link(np,1);
 71         else
 72         {
 73             q=son[p][x];
 74             if (step[p]+1==step[q]) fa[np]=q,Link(np,q);
 75             else
 76             {
 77                 nq=++cnt; step[nq]=step[p]+1;
 78                 memcpy(son[nq],son[q],sizeof(son[q]));
 79                 Link(nq,fa[q]); Cut(q,fa[q]); Link(q,nq); Link(np,nq);
 80                 fa[nq]=fa[q]; fa[q]=fa[np]=nq;
 81                 while (son[p][x]==q) son[p][x]=nq,p=fa[p];
 82             }
 83         }
 84     }
 85     int Query(char s[])
 86     {
 87         Make_root(1);
 88         int now=1, len=strlen(s);
 89         for (int i=0; i<len; ++i)
 90             if (son[now][s[i]-'A']) now=son[now][s[i]-'A'];
 91             else return 0;
 92         Access(now); Splay(now);
 93         return Size[now]-Size[Son[now][0]];
 94     }
 95 }SAM;
 96
 97 void Decode(char *s,int mask)
 98 {
 99     int len=strlen(s);
100     for(int i=0; i<len; ++i)
101     {
102         mask=(mask*131+i)%len;
103         swap(s[i],s[mask]);
104     }
105 }
106
107 int main()
108 {
109     scanf("%d",&T);
110     scanf("%s",s);
111     int len=strlen(s);
112     for (int i=0; i<len; ++i)
113         SAM.Insert(s[i]-'A');
114     while (T--)
115     {
116         scanf("%s%s",opt,s);
117         int len=strlen(s);
118         Decode(s,mask);
119         if (opt[0]=='A')
120             for (int i=0; i<len; ++i)
121                 SAM.Insert(s[i]-'A');
122         else
123         {
124             int ans=SAM.Query(s);
125             printf("%d\n",ans);
126             mask^=ans;
127         }
128     }
129 }

转载于:https://www.cnblogs.com/refun/p/9378216.html

BZOJ2555:SubString(SAM,LCT)相关推荐

  1. SubString SAM+LCT

    P5212 SubString 题意 给出字符串S和操作次数Q ADD:往S后继续加一个字符串 QUERY:求给出的字符串在S中出现次数 考虑SAM,插入是O(n)的,查询位置时O(n)的,问题是怎么 ...

  2. 2019.03.01 bzoj2555: SubString(sam+lct)

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

  3. Bzoj2555 SubString

    Time Limit: 30 Sec  Memory Limit: 512 MB Submit: 2430  Solved: 719 Description 懒得写背景了,给你一个字符串init,要求 ...

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

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

  5. 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 ...

  6. 平衡树+LCT全纪录

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

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

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

  8. 【BZOJ4545】DQS的trie

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

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

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

  10. ZR2019暑期集训游记

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

最新文章

  1. visualSVN-server的安装图解
  2. 平方的观测值表概率_茆诗松的概率论与数理统计(第六章)
  3. DeepLab v2的摘要部分(翻译加理解)
  4. [转].NET学习网站收集
  5. HUST 1541 Student’s question
  6. Linux内存page,Linux虚拟内存管理 - Page Table的作用
  7. 大白话带你梳理一下Dubbo的那些事儿
  8. Mybatis(6)CURD增删改查操作
  9. MySQL的初识(python开发者的第一印象)
  10. 编程实现 带符号减法溢出判断
  11. ubuntu--雷鸟只能收邮件不能发邮件
  12. Java Annotaion认识
  13. Android点赞头像列表
  14. JavaScript函数 思维导图
  15. 第一代计算机的拼音,计算机系列拼音
  16. 从模型制作(3dmax)到网页显示(babylonjs)全过程介绍
  17. 动态内存分配实现冒泡排序
  18. 使用曲面细分渲染毛发
  19. 坚果云同步的HTML编辑器,我的浏览器标签同步方案:坚果云+Floccus
  20. 笔记本配置连接打印机

热门文章

  1. 第三天:完善数据层(controller)真正对接数据库Mysql
  2. ThinkPhp 使用 PHP_XLSXWriter 代替 PHPExcel 百万级数据单次导出
  3. 刚接触新工作的程序员:直接运行include
  4. 使用jdk提示Assistive Technology not found: org.GNOME.Accessibility.AtkWrapper
  5. IDEA中安装TeaVM插件
  6. Dx unsupported class file version 52.0 Conversion to Dalvik format failed with error 1
  7. LINUX下载编译libav
  8. LINUX doubango编译中prefix参数无效
  9. JAVA对象,直接新建跟反射新建,有区别
  10. C中遇到错误error: jump to label [-fpermissive]的解决办法