[BZOJ 2555] SubString
Substring
题意
题面
给定一个初始字符串, 要求支持在这个字符串后添加字符串/查询某个字符串作为子串的出现次数.
强制在线.
长度 \(\le600000\),询问次数 \(\le10000\),询问总长度 \(\le3000000\).
题解
看上去好像可以KMP增量构造的样子
实际上不行 (每次询问都得遍历一遍原串)
考虑用另一个可以支持快速扩展的维护字符串的算法: SAM.
但是SAM增量构造的时候某个状态对应的 right
集合大小(也就是对应子串的出现次数)是 prt
树上的子树和的形式. 而且这个树的形态会产生改变(又是烦人的nq
结点搞的事情).
注意到这里求子树和的时候不会换根, 于是我们可以在每次 link
的时候都把当前点对所有祖先的贡献都通过一次链上操作累加上去. 于是就可以比较容易地用LCT维护了.
然而写假了好几次
一开始写假是因为 Decode
出了锅调了很久...因为我一直以为 mask
在 Decode
的时候也会变...
后来写假是因为 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相关推荐
- BZOJ 2555: SubString [后缀自动机 LCT]
2555: SubString Time Limit: 30 Sec Memory Limit: 512 MB Submit: 2045 Solved: 583 [Submit][Status][ ...
- [bzoj 2555]Substring
传送门 Description 给你一个字符串\(init\),要求你支持两个操作 (1):在当前字符串的后面插入一个字符串 (2):询问字符串s在当前字符串中出现了几次?(作为连续子串) 你必须在线 ...
- BZOJ.2555.SubString(后缀自动机 LCT)
题目链接 \(Description\) 给你一个字符串init,要求支持两个操作: (1)在当前字符串的后面插入一个字符串s (2)询问字符串s在当前字符串中出现了几次(作为连续子串) 强制在线. ...
- qt string内带变量_QT QString 很全的使用 (转)
QString, QByteArray, 和 QVariant这三个类和容器有许多相同之处,并且在一些情况下可以被当作特殊的容器. 同样,像容器,这些类使用隐式共享来优化内存和速度. 我们将从QStr ...
- 做题记录 To 2019.2.13
2019-01-18 4543: [POI2014]Hotel加强版:长链剖分+树形dp. 3653: 谈笑风生:dfs序+主席树. POJ 3678 Katu Puzzle:2-sat问题,给n个变 ...
- [颓废史]蒟蒻的刷题记录
QAQ蒟蒻一枚,其实我就是来提供水题库的. 以下记录从2016年开始. 1.1 1227: [SDOI2009]虔诚的墓主人 树状数组+离散化 3132: 上帝造题的七分钟 树状数组 二维区间加减+查 ...
- 后缀自动机/回文自动机/AC自动机/序列自动机----各种自动机(自冻鸡) 题目泛做...
题目1 BZOJ 3676 APIO2014 回文串 算法讨论: cnt表示回文自动机上每个结点回文串出现的次数.这是回文自动机的定义考查题. 1 #include <cstdlib> 2 ...
- BZOJ4768: 2555加强版之wxh loves substring
很显然的后缀平衡树 一开始以为要可持久化 发现根本不用.. treap的常数要死人啊? 我好像T光光了? 寄刀片寄刀片 #include<cstdio> #include<iostr ...
- bzoj4768: wxh loves substring //后缀平衡树
bzoj4768: 2555加强版之wxh loves substring 题意 给出一个字符串,要求资瓷: 在末尾添加/删除字符: 询问一个串的出现次数. 原串长与变化长度之和<=800000 ...
最新文章
- Linux Shell简介
- 企业的任何方法均可融入敏捷技术
- SQL2005-使用openrowset 里读取excel文件
- dockerfile 安装mysql_dockerfile构建mysql镜像
- java 千位分隔,如何在Java中设置千位分隔符?
- jemalloc java_jemalloc源码结构分析
- 为什么不同文化中都会发现圆形房屋
- 渗透之——SQLMap参数说明
- python 回归方程及回归系数的显著性检验_使用Excel和python来做回归分析
- ios 凭据验证_苹果内购服务器验证凭证回执Data
- 一个超级超级准的心理测试
- 零基础转行到软件测试如何拿到所谓的高薪?
- 一个屌丝程序员的青春(二六五)
- java中 continue outer, break inner 简解
- ‘xxxx’ does not name a type报错处理方法
- 从WebService到面向服务架构SOA理解【二】
- java图片压缩工具类
- 阿里“无影” | 未来每个人在云上都会有自己的主机
- 相似图片搜索的原理(一)
- ntp实现多台服务器时间同步[实测]
热门文章
- ubuntu12.04上安装flashcahce
- 树形控件Tree Control
- Windows8应用生命周期 Metro Style Apps Lifecycle
- 【BZOJ1572】【usaco 2009 open】工作安排job
- 批量Excel数据导入Oracle数据库
- 67.数据库系统的三级模式
- 航“空”、航“天”大不同
- STM32F103xC、STM32F103xD和STM32F103xE增强型模块框图 与 时钟树
- java 基础api实现上传,上传文件到7牛云存储的java api一个简单的demo实现
- python 事务操作_Python实现完整的事务操作示例