当前位置:网站首页>【2022国赛模拟】白楼剑——SAM、回滚莫队、二次离线
【2022国赛模拟】白楼剑——SAM、回滚莫队、二次离线
2022-07-26 14:30:00 【偶耶XJX】
非原题链接
题目描述


题解
遇到这种找子串出现次数的题,第一时间想到 SAM。
对 S 2 S_2 S2 建出 SAM 后,我们可以在其 p a r e n t t r e e \rm parent\,tree parenttree 上做一些预处理,记录一下每个节点的祖先节点答案的最大值。然后在 S 1 S_1 S1 的对应区间内做扫描线,每次找到能够匹配的最长后缀时就可以快速求得它对答案的贡献。
从上面的暴力过程发现,我们能够较快地将询问区间扩大 1,并同时维护答案,而缩小就不行。于是在思考在线或者 P o l y ( log n ) Poly(\log n) Poly(logn) 解法未果后,我们可以自然地想到使用回滚莫队。
由于左右两边都要扩展,所以需要建出正串和反串的 SAM。由于回滚莫队往右扩展的起点只有 n \sqrt{n} n 个,所以可以暴力预处理。
往左扩展的话,预处理定位出 S 1 S_1 S1 上每个位置往后能匹配的最长串在 SAM 上的节点后,每次扩展就只需要用一个倍增跳祖先就可以定位到区间内子串对应节点,然后 O ( 1 ) O(1) O(1) 算答案即可。
于是得到一个 O ( n n log n ) O(n\sqrt{n}\log n) O(nnlogn) 的做法,我的常数显然是过不了的。
考虑把这个 log n \log n logn 给优化掉,也就是不用倍增找祖先,而用更快的方法。
一次离线已经走到尽头了,我们可以考虑二次离线。具体做法是,把上面找祖先的请求离线下来挂到 SAM 上,然后在 SAM 上做 DFS,用一个数据结构维护每种长度对应哪个祖先。
分析一下操作数发现,修改次数是 O ( n ) O(n) O(n) 的,查询次数是 O ( n n ) O(n\sqrt{n}) O(nn) 的,所以再用一个分块 O ( n ) O(\sqrt{n}) O(n) 修改, O ( 1 ) O(1) O(1) 查询即可。
最终复杂度优化为 O ( n n ) O(n\sqrt{n}) O(nn),用预先reserve技巧卡常效果更佳。
代码
#include<bits/stdc++.h>//JZM yyds!!
#define ll long long
#define lll __int128
#define uns unsigned
#define fi first
#define se second
#define IF (it->fi)
#define IS (it->se)
#define END putchar('\n')
#define lowbit(x) ((x)&-(x))
#define inline jzmyyds
using namespace std;
const int MAXN=1e5+3;
const ll INF=1e17;
ll read(){
ll x=0;bool f=1;char s=getchar();
while((s<'0'||s>'9')&&s>0){
if(s=='-')f^=1;s=getchar();}
while(s>='0'&&s<='9')x=(x<<1)+(x<<3)+(s^48),s=getchar();
return f?x:-x;
}
int ptf[50],lpt;
void print(ll x,char c='\n'){
if(x<0)putchar('-'),x=-x;
ptf[lpt=1]=x%10;
while(x>9)x/=10,ptf[++lpt]=x%10;
while(lpt>0)putchar(ptf[lpt--]^48);
if(c>0)putchar(c);
}
using pii=pair<int,int>;
char s[MAXN],in[MAXN];
ll qa[33000005],fx[330][MAXN];
int QN,B,BB,n,m,q,pt[MAXN],lt[MAXN],L[MAXN],R[MAXN];
struct itn{
int ch[26],fa,len;};
int bf[MAXN],bg[330];
void cov(int L,int R,int d){
for(int e=(L-1)/BB,l=e*BB+1;l<=m;l+=BB,e++){
int r=min(m,l+BB-1);
if(l>R)break;
if(l>=L&&r<=R)bg[e]=d;
else for(int i=max(l,L),lm=min(R,r);i<=lm;i++)bf[i]=d;
}
}
void clr(int L,int R){
for(int e=(L-1)/BB,l=e*BB+1;l<=m;l+=BB,e++){
int r=min(m,l+BB-1);
if(l>R)break;
if(l>=L&&r<=R)bg[e]=0;
else for(int i=max(l,L),lm=min(R,r);i<=lm;i++)bf[i]=0;
}
}
struct SAM{
itn sam[MAXN<<1];
int las,tot,t[MAXN<<1],sv[MAXN<<1];
ll pm[MAXN<<1];
vector<int>G[MAXN<<1];
vector<pii>sk[MAXN<<1];
SAM(){
las=tot=1;}
void samadd(int c){
int p=las,np=las=++tot;sam[np].len=sam[p].len+1;
for(;p&&!sam[p].ch[c];p=sam[p].fa)sam[p].ch[c]=np;
if(!p)sam[np].fa=1;
else{
int q=sam[p].ch[c],nq;
if(sam[q].len==sam[p].len+1)sam[np].fa=q;
else{
nq=++tot,sam[nq]=sam[q],sam[nq].len=sam[p].len+1;
sam[q].fa=sam[np].fa=nq;
for(;p&&sam[p].ch[c]==q;p=sam[p].fa)sam[p].ch[c]=nq;
}
}t[np]++;
}
void pdfs(int x){
for(int&v:G[x])pdfs(v),t[x]+=t[v];
}
void build(){
for(int i=2;i<=tot;i++)G[sam[i].fa].push_back(i);
for(int i=1;i<=tot;i++)sk[i].reserve(sv[i]);
pdfs(1);
}
void dfs(int x,ll PM,bool dt){
pm[x]=PM,PM=max(PM,1ll*sam[x].len*t[x]);
if(x>1&&dt)cov(sam[sam[x].fa].len+1,sam[x].len,x);
for(auto&it:sk[x]){
if(it.fi>=sam[x].len)qa[it.se]=PM;
else{
int y=max(bf[it.fi],bg[(it.fi-1)/BB]);
qa[it.se]=max(1ll*it.fi*t[y],pm[y]);
}
}
for(int&v:G[x])dfs(v,PM,dt);
if(x>1&&dt)clr(sam[sam[x].fa].len+1,sam[x].len);
}
}P,Q;
int main()
{
freopen("c.in","r",stdin);
freopen("c.out","w",stdout);
*new(int)=scanf("%s%s",s+1,in+1);
n=strlen(s+1),m=strlen(in+1),B=ceil(sqrt(n)),BB=ceil(sqrt(m));
for(int i=1;i<=m;i++)P.samadd(in[i]-'a');
P.build(),P.dfs(1,0,0);
for(int l=1,e=0;l<=n;l+=B,e++){
int p=1,le=0;
for(int i=l;i<=n;i++){
int c=s[i]-'a';
while(p>1&&!P.sam[p].ch[c])p=P.sam[p].fa;
le=min(le,P.sam[p].len);
if(P.sam[p].ch[c])p=P.sam[p].ch[c],le++;
fx[e][i]=max(fx[e][i-1],max(P.pm[p],1ll*le*P.t[p]));
}
}
for(int i=m;i>0;i--)Q.samadd(in[i]-'a');
for(int i=n,le=0,p=1;i>0;i--){
int c=s[i]-'a';
while(p>1&&!Q.sam[p].ch[c])p=Q.sam[p].fa;
le=min(le,Q.sam[p].len);
if(Q.sam[p].ch[c])p=Q.sam[p].ch[c],le++;
pt[i]=p,lt[i]=le;
}
//由于问题特殊,回滚莫队可以不用排序,直接用预处理的值现算
q=read();
for(int i=1;i<=q;i++){
int l=L[i]=read(),r=R[i]=read(),el=(l-1)/B,er=(r-1)/B;
if(el==er){
for(int j=r;j>=l;j--)Q.sv[pt[j]]++;
}else for(int j=el*B+B;j>=l;j--)Q.sv[pt[j]]++;
}Q.build(),QN=0;
for(int i=1;i<=q;i++){
//二次离线
int l=L[i],r=R[i],el=(l-1)/B,er=(r-1)/B;
if(el==er){
for(int j=r;j>=l;j--)
Q.sk[pt[j]].emplace_back(min(r-j+1,lt[j]),++QN);
}else{
for(int j=el*B+B;j>=l;j--)
Q.sk[pt[j]].emplace_back(min(r-j+1,lt[j]),++QN);
}
}Q.dfs(1,0,1),QN=0;
for(int i=1;i<=q;i++){
int l=L[i],r=R[i],el=(l-1)/B,er=(r-1)/B;
ll ans=0;
if(el==er){
for(int j=r;j>=l;j--)ans=max(ans,qa[++QN]);
}else{
ans=fx[el+1][r];
for(int j=el*B+B;j>=l;j--)ans=max(ans,qa[++QN]);
}
print(ans);
}
return 0;
}
边栏推荐
- What is restful style and its four specific implementation forms
- Disease knowledge discovery based on spo semantic triples
- [ostep] 04 virtualized CPU - process scheduling strategy
- 请问下大家,flink sql有没有办法不输出update_before?
- Devops system of "cloud native" kubesphere pluggable components
- 基于用户画像的在线健康社区用户流失预测研究
- First knowledge of opencv4.x --- image perspective transformation
- SP export map to Maya
- Seata deployment and microservice integration
- 【愚公系列】2022年7月 Go教学课程 017-分支结构之IF
猜你喜欢

基于标签嵌入注意力机制的多任务文本分类模型

使用cpolar建立一个商业网站(申请网站安全证书)

31. Opinion based relational pivoting forcross domain aspect term extraction reading notes

VP video structured framework

Research on Chinese medicine assisted diagnosis and treatment scheme integrating multiple natural language processing tasks -- taking diabetes as an example
![[untitled]](/img/50/7aa01f1d8657700a11cbc26290804a.png)
[untitled]

Use cpolar to build a commercial website (apply for website security certificate)

Multi task text classification model based on tag embedded attention mechanism

GOM登录器配置免费版生成图文教程

MLX90640 红外热成像仪测温传感器模块开发笔记(六)
随机推荐
[draw with toolbar]
基于专利多属性融合的技术主题划分方法研究
作业7.25 排序与查找
First knowledge of opencv4.x --- image perspective transformation
Leetcode1170- compare the occurrence frequency of the minimum letter of the string (the corresponding occurrence frequency of each string minimum element in the map set storage array)
基于用户画像的在线健康社区用户流失预测研究
请问下大家,flink sql有没有办法不输出update_before?
ISCC2021 LOCKK题解
What is the problem of the time series database that has been developed for 5 years?
Transc knowledge representation model
Maya imports the model into unity
基于标签嵌入注意力机制的多任务文本分类模型
基于SPO语义三元组的疾病知识发现
研发了 5 年的时序数据库,到底要解决什么问题?
TransC知识表示模型
C# NanUI 相关功能整合
『BaGet』带你一分钟搭建自己的私有NuGet服务器
VP video structured framework
[ostep] 02 virtualized CPU - process
Kubernetes----Pod配置资源配额