Substring

题意

题面

给定一个初始字符串, 要求支持在这个字符串后添加字符串/查询某个字符串作为子串的出现次数.

强制在线.

长度 \(\le600000\),询问次数 \(\le10000\),询问总长度 \(\le3000000\).

题解

看上去好像可以KMP增量构造的样子

实际上不行 (每次询问都得遍历一遍原串)

考虑用另一个可以支持快速扩展的维护字符串的算法: SAM.

但是SAM增量构造的时候某个状态对应的 right 集合大小(也就是对应子串的出现次数)是 prt 树上的子树和的形式. 而且这个树的形态会产生改变(又是烦人的nq结点搞的事情).

注意到这里求子树和的时候不会换根, 于是我们可以在每次 link 的时候都把当前点对所有祖先的贡献都通过一次链上操作累加上去. 于是就可以比较容易地用LCT维护了.

然而写假了好几次

一开始写假是因为 Decode 出了锅调了很久...因为我一直以为 maskDecode 的时候也会变...

后来写假是因为 link/cut 的时候没有把整个子树的贡献都累加上去 (这数据比较生草...这么大的错误只挂了一个点...)

参考代码

#include <bits/stdc++.h>const int MAXN=2e6+10;
int size[MAXN];#define lch chd[0]
#define rch chd[1]
#define kch chd[k]
#define xch chd[k^1]struct LinkCutTree{struct Node{int val;int add;bool rev;Node* prt;Node* pprt;Node* chd[2];Node(int x):val(x),add(0),rev(false),prt(NULL),pprt(NULL){this->lch=this->rch=NULL;}void Flip(){if(this!=NULL){this->rev=!this->rev;std::swap(this->lch,this->rch);}}void Add(int x){if(this!=NULL){this->val+=x;this->add+=x;}}void PushDown(){if(this->add!=0){this->lch->Add(this->add);this->rch->Add(this->add);this->add=0;}if(this->rev){this->lch->Flip();this->rch->Flip();this->rev=false;}}};std::vector<Node*> N;LinkCutTree():N(1){}void Rotate(Node* root,int k){Node* tmp=root->xch;root->PushDown();tmp->PushDown();tmp->prt=root->prt;if(root->prt==NULL){tmp->pprt=root->pprt;root->pprt=NULL;}else if(root->prt->lch==root)root->prt->lch=tmp;elseroot->prt->rch=tmp;root->xch=tmp->kch;if(root->xch!=NULL)root->xch->prt=root;tmp->kch=root;root->prt=tmp;}void Splay(Node* root){while(root->prt!=NULL){int k=root->prt->lch==root;if(root->prt->prt==NULL)Rotate(root->prt,k);else{int d=root->prt->prt->lch==root->prt;Rotate(k==d?root->prt->prt:root->prt,k);Rotate(root->prt,d);}}}void Expose(Node* root){Splay(root);root->PushDown();if(root->rch!=NULL){root->rch->prt=NULL;root->rch->pprt=root;root->rch=NULL;}}bool Splice(Node* root){Splay(root);if(root->pprt==NULL)return false;Expose(root->pprt);root->pprt->rch=root;root->prt=root->pprt;root->pprt=NULL;return true;}void Access(Node* root){Expose(root);while(Splice(root));assert(root->pprt==0&&root->prt==0);}void Evert(Node* root){Access(root);root->Flip();}void Add(int y,int d){Evert(N[1]);Access(N[y]);N[y]->Add(d);}void Link(int prt,int son){Evert(N[son]);N[son]->pprt=N[prt];Evert(N[1]);Access(N[prt]);N[prt]->Add(N[son]->val);}void Cut(int prt,int son){Evert(N[1]);Access(N[son]);Access(N[prt]);N[prt]->Add(-N[son]->val);Access(N[son]);N[son]->PushDown();N[son]->lch->prt=NULL;N[son]->lch=NULL;}int Query(int x){Access(N[x]);return N[x]->val;}void MakeTree(int x){N.push_back(new Node(x));}
}*T=new LinkCutTree();int q;
int cnt=1;
int root=1;
int last=1;
char s[MAXN];
int prt[MAXN];
int len[MAXN];
std::map<char,int> chd[MAXN];int Query(char*);
void Extend(char);
void Extend(char*);
void Decode(char*,int);int main(){scanf("%d",&q);scanf("%s",s);T->MakeTree(0);Extend(s);int mask=0;while(q--){scanf("%s",s);if(*s=='A'){scanf("%s",s);Decode(s,mask);Extend(s);}else{scanf("%s",s);Decode(s,mask);int x=Query(s);mask^=x;printf("%d\n",x);}}return 0;
}int Query(char* s){int cur=root;while(*s!='\0'){if(!chd[cur].count(*s))return 0;elsecur=chd[cur][*s];++s;}return T->Query(cur);
}void Decode(char* s,int mask){int len=strlen(s);for(int i=0;i<len;i++){mask=(mask*131+i)%len;char t=s[i];s[i]=s[mask];s[mask]=t;}
}void Extend(char* s){while(*s!='\0')Extend(*(s++));
}void Extend(char x){int p=last;int np=++cnt;T->MakeTree(1);size[last=np]=1;len[np]=len[p]+1;while(p&&!chd[p].count(x))chd[p][x]=np,p=prt[p];if(p==0)prt[np]=root;else{int q=chd[p][x];if(len[q]==len[p]+1)prt[np]=q;else{int nq=++cnt;T->MakeTree(0);chd[nq]=chd[q];prt[nq]=prt[q];T->Cut(prt[q],q);T->Link(prt[nq],nq);prt[q]=nq;T->Link(nq,q);prt[np]=nq;len[nq]=len[p]+1;while(p&&chd[p][x]==q)chd[p][x]=nq,p=prt[p];}}T->Link(prt[np],np);
}

转载于:https://www.cnblogs.com/rvalue/p/10359563.html

[BZOJ 2555] SubString相关推荐

  1. BZOJ 2555: SubString [后缀自动机 LCT]

    2555: SubString Time Limit: 30 Sec  Memory Limit: 512 MB Submit: 2045  Solved: 583 [Submit][Status][ ...

  2. [bzoj 2555]Substring

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

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

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

  4. qt string内带变量_QT QString 很全的使用 (转)

    QString, QByteArray, 和 QVariant这三个类和容器有许多相同之处,并且在一些情况下可以被当作特殊的容器. 同样,像容器,这些类使用隐式共享来优化内存和速度. 我们将从QStr ...

  5. 做题记录 To 2019.2.13

    2019-01-18 4543: [POI2014]Hotel加强版:长链剖分+树形dp. 3653: 谈笑风生:dfs序+主席树. POJ 3678 Katu Puzzle:2-sat问题,给n个变 ...

  6. [颓废史]蒟蒻的刷题记录

    QAQ蒟蒻一枚,其实我就是来提供水题库的. 以下记录从2016年开始. 1.1 1227: [SDOI2009]虔诚的墓主人 树状数组+离散化 3132: 上帝造题的七分钟 树状数组 二维区间加减+查 ...

  7. 后缀自动机/回文自动机/AC自动机/序列自动机----各种自动机(自冻鸡) 题目泛做...

    题目1 BZOJ 3676 APIO2014 回文串 算法讨论: cnt表示回文自动机上每个结点回文串出现的次数.这是回文自动机的定义考查题. 1 #include <cstdlib> 2 ...

  8. BZOJ4768: 2555加强版之wxh loves substring

    很显然的后缀平衡树 一开始以为要可持久化 发现根本不用.. treap的常数要死人啊? 我好像T光光了? 寄刀片寄刀片 #include<cstdio> #include<iostr ...

  9. bzoj4768: wxh loves substring //后缀平衡树

    bzoj4768: 2555加强版之wxh loves substring 题意 给出一个字符串,要求资瓷: 在末尾添加/删除字符: 询问一个串的出现次数. 原串长与变化长度之和<=800000 ...

最新文章

  1. Linux Shell简介
  2. 企业的任何方法均可融入敏捷技术
  3. SQL2005-使用openrowset 里读取excel文件
  4. dockerfile 安装mysql_dockerfile构建mysql镜像
  5. java 千位分隔,如何在Java中设置千位分隔符?
  6. jemalloc java_jemalloc源码结构分析
  7. 为什么不同文化中都会发现圆形房屋
  8. 渗透之——SQLMap参数说明
  9. python 回归方程及回归系数的显著性检验_使用Excel和python来做回归分析
  10. ios 凭据验证_苹果内购服务器验证凭证回执Data
  11. 一个超级超级准的心理测试
  12. 零基础转行到软件测试如何拿到所谓的高薪?
  13. 一个屌丝程序员的青春(二六五)
  14. java中 continue outer, break inner 简解
  15. ‘xxxx’ does not name a type报错处理方法
  16. 从WebService到面向服务架构SOA理解【二】
  17. java图片压缩工具类
  18. 阿里“无影” | 未来每个人在云上都会有自己的主机
  19. 相似图片搜索的原理(一)
  20. ntp实现多台服务器时间同步[实测]

热门文章

  1. ubuntu12.04上安装flashcahce
  2. 树形控件Tree Control
  3. Windows8应用生命周期 Metro Style Apps Lifecycle
  4. 【BZOJ1572】【usaco 2009 open】工作安排job
  5. 批量Excel数据导入Oracle数据库
  6. 67.数据库系统的三级模式
  7. 航“空”、航“天”大不同
  8. STM32F103xC、STM32F103xD和STM32F103xE增强型模块框图 与 时钟树
  9. java 基础api实现上传,上传文件到7牛云存储的java api一个简单的demo实现
  10. python 事务操作_Python实现完整的事务操作示例