题面

传送门

题解

后缀平衡树是个啥啊我不会啊……

那么我们来考虑一下\(SAM\)的做法好了

不难发现它的本义是要我们维护一棵\(trie\)树,并求出\(trie\)树上每一个节点到根的这段串的不同子串个数,而显然一个串的不同子串个数就是它的\(SAM\)上每一个节点的\(len[p]-len[fa[p]]\)之和

那么我们对这个\(trie\)建一个广义\(SAM\),这个\(SAM\)一定包含每一个路径的\(SAM\)

我们对每一个这棵\(trie\)上的每一个节点记录一个\(pos\),表示这个节点插入在\(SAM\)上的哪一个位置,然后把\(SAM\)的\(parent\)树记录一下\(dfs\)序

那么操作可以看做是在\(parent\)树上插入和删除节点,以插入为例,我们可以直接加上\(p\)到根节点的\(len\),但是这样有可能会算多,于是我们要减去\(p\)的前驱(以\(dfs\)序为顺序排列)和\(p\)的\(LCA\)的\(len\),以及和它的后继的\(LCA\)的\(len\)。但是这样可能又减多了,所以还需要加上它的前驱和后继的\(LCA\)的\(len\)

然后没有然后了

//minamoto
#include<bits/stdc++.h>
#define R register
#define ll long long
#define IT set<int>::iterator
#define fp(i,a,b) for(R int i=(a),I=(b)+1;i<I;++i)
#define fd(i,a,b) for(R int i=(a),I=(b)-1;i>I;--i)
#define go(u) for(int i=head[u],v=e[i].v;i;i=e[i].nx,v=e[i].v)
using namespace std;
char buf[1<<21],*p1=buf,*p2=buf;
inline char getc(){return p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++;}
int read(char *s){
R int len=0;R char ch;while(((ch=getc())>'z'||ch<'a')&&ch!='-');
for(s[++len]=ch;(ch=getc())>='a'&&ch<='z'||ch=='-';s[++len]=ch);
return s[len+1]='\0',len;
}
char sr[1<<21],z[20];int C=-1,Z=0;
inline void Ot(){fwrite(sr,1,C+1,stdout),C=-1;}
void print(R ll x){
if(C>1<<20)Ot();if(x<0)sr[++C]='-',x=-x;
while(z[++Z]=x%10+48,x/=10);
while(sr[++C]=z[Z],--Z);sr[++C]='\n';
}
const int N=2e5+5;
struct eg{int v,nx;}e[N<<1];int head[N],tot;
inline void add(R int u,R int v){e[++tot]={v,head[u]},head[u]=tot;}
char t[N];int l[N],ch[N][26],fa[N],pos[N],st[N],dep[N],dfn[N],top[N],sz[N],son[N],rk[N];
int las=1,cnt=1,n,tim;set<int> s;ll res;
void ins(int c,int p=las){
if(ch[p][c]){
int q=ch[p][c];
if(l[q]==l[p]+1)las=q;
else{
int nq=las=++cnt;l[nq]=l[p]+1;
memcpy(ch[nq],ch[q],4*26);
fa[nq]=fa[q],fa[q]=nq;
for(;p&&ch[p][c]==q;p=fa[p])ch[p][c]=nq;
}
}else{
int np=las=++cnt;l[np]=l[p]+1;
for(;p&&!ch[p][c];p=fa[p])ch[p][c]=np;
if(!p)fa[np]=1;
else{
int q=ch[p][c];
if(l[q]==l[p]+1)fa[np]=q;
else{
int nq=++cnt;l[nq]=l[p]+1;
memcpy(ch[nq],ch[q],4*26);
fa[nq]=fa[q],fa[q]=fa[np]=nq;
for(;p&&ch[p][c]==q;p=fa[p])ch[p][c]=nq;
}
}
}
}
void dfs1(int u){
sz[u]=1,dep[u]=dep[fa[u]]+1;
go(u){
dfs1(v),sz[u]+=sz[v];
sz[v]>sz[son[u]]?son[u]=v:0;
}
}
void dfs2(int u,int t){
top[u]=t,rk[dfn[u]=++tim]=u;
if(!son[u])return;
dfs2(son[u],t);
go(u)if(!top[v])dfs2(v,v);
}
int LCA(int u,int v){
while(top[u]!=top[v]){
dep[top[u]]<dep[top[v]]?(swap(u,v),0):0;
u=fa[top[u]];
}return dep[u]<dep[v]?u:v;
}
void update(int u,int op){
if(op==1)s.insert(u);
IT itl,itr,it;itl=itr=it=s.find(u);
res+=op*l[rk[u]];
if(itl!=s.begin())--itl,res-=op*l[LCA(rk[u],rk[*itl])];
if(itr!=--s.end())++itr,res-=op*l[LCA(rk[u],rk[*itr])];
if(itl!=it&&itr!=it)res+=op*l[LCA(rk[*itl],rk[*itr])];
if(op==-1)s.erase(u);
}
int main(){
// freopen("testdata.in","r",stdin);
n=read(t);
st[0]=1;
for(R int i=1,top=0;i<=n;++i)if(t[i]=='-')--top;
else las=st[top],ins(t[i]-'a'),pos[i]=st[++top]=las;
fp(i,2,cnt)add(fa[i],i);
dfs1(1),dfs2(1,1);
for(R int i=1,top=0;i<=n;++i){
if(t[i]=='-')update(dfn[pos[st[top--]]],-1);
else update(dfn[pos[st[++top]=i]],1);
print(res);
}
return Ot(),0;
}

【bzoj5084】 hashit(广义SAM+set)的更多相关文章

  1. bzoj5084 hashit 广义SAM+树链的并

    题目传送门 https://lydsy.com/JudgeOnline/problem.php?id=5084 题解 考虑平常对于静态问题,我们应该如何用 SAM 求本质不同的子串个数. 对于一个常规 ...

  2. 【bzoj5084】hashit 广义后缀自动机+树链的并+STL-set

    题目描述 你有一个字符串S,一开始为空串,要求支持两种操作 在S后面加入字母C 删除S最后一个字母 问每次操作后S有多少个两两不同的连续子串 输入 一行一个字符串Q,表示对S的操作 如果第i个字母是小 ...

  3. 【HDU 4436】 str2int (广义SAM)

    str2int Problem Description In this problem, you are given several strings that contain only digits ...

  4. 【BZOJ 3926】 [Zjoi2015]诸神眷顾的幻想乡 (广义SAM)

    3926: [Zjoi2015]诸神眷顾的幻想乡 Time Limit: 10 Sec  Memory Limit: 512 MBSubmit: 974  Solved: 573 Descriptio ...

  5. 【BZOJ 3473】 字符串 (后缀数组+RMQ+二分 | 广义SAM)

    3473: 字符串 Description 给定n个字符串,询问每个字符串有多少子串(不包括空串)是所有n个字符串中至少k个字符串的子串? Input 第一行两个整数n,k. 接下来n行每行一个字符串 ...

  6. luogu3346 诸神眷顾的幻想乡 (广义SAM)

    首先,让每一个叶节点做一次树根的话,每个路径一定至少有一次会变成直上直下的 于是对于每个叶节点作为根产生的20个trie树,把它们建到同一个广义SAM里 建法是对每个trie dfs去建,last就是 ...

  7. loj#6031. 「雅礼集训 2017 Day1」字符串(SAM 广义SAM 数据分治)

    题意 链接 Sol \(10^5\)次询问每次询问\(10^5\)个区间..这种题第一感觉就是根号/数据分治的模型. \(K\)是个定值这个很关键. 考虑\(K\)比较小的情况,可以直接暴力建SAM, ...

  8. Luogu P3181 [HAOI2016]找相同字符 广义$SAM$

    题目链接 \(Click\) \(Here\) 设一个串\(s\)在\(A\)中出现\(cnt[s][1]\)次,在\(B\)中出现\(cnt[s][2]\)次,我们要求的就是: \[\sum cnt ...

  9. BZOJ5084[hashit]

    题解: 后缀自动机 我们可以通过建立trie 把询问变成询问一些点的并 把trie建立成SAM和广义SAM基本相同,就是在父亲和儿子之间连边 然后就变成了询问树链的并 我们可以发现答案=sigma d ...

随机推荐

  1. MD5类库(hex_md5)

    /*  * A JavaScript implementation of the RSA Data Security, Inc. MD5 Message  * Digest Algorithm, as ...

  2. C#匿名类型 - Anonymous Types

    [C#匿名类型 - Anonymous Types] Anonymous types provide a convenient way to encapsulate a set of read-onl ...

  3. git服务器搭建问题

    CentOS6.5本地搭建. 对于图形化的系统,可以联网,然后CTRL+ALT+F2可以切换到命令行,CTRL+ALT+F1可以切换回桌面图形化. 可以用SSH和FTP来连接服务器和传文件.   (1 ...

  4. Gym101128F:Landscaping

    题意 有一片h*w的草坪,要把每一行从左到右修剪一遍,每一列从上到下修剪一遍.每个草坪要么是高低要么是平地.割草机从高地到平地或者从平地到高地,需要花费a.也可以把平地变为高地或者把高地变为平地,花费 ...

  5. 使用jquery修改表单的提交地址

    基本思路: 通过使用jquery选择器得到对应表单的jquery对象,然后使用attr方法修改对应的action 示例程序一: 默认情况下,该表单会提交到page_one.html 点击button之 ...

  6. nginx内置变量详解-乾颐堂

    nginx的配置文件中可以使用的内置变量以美元符$开始,也有人叫全局变量.其中,部分预定义的变量的值是可以改变的. $arg_PARAMETER 这个变量值为:GET请求中变量名PARAMETER参数 ...

  7. Sprig 面试中 问及 DI,IOC, AOP

    面向切面编程,把散落在程序中的公共部分提取出来,做成切面类,这样的好处在于,代码的可重用,一旦涉及到该功能的需求发生变化,只要修改该代码就行,否则,你要到处修改,如果只要修改1.2处那还可以接受,万一 ...

  8. CRISPR/Cas9基因敲除原理及实验建议

    CRISPR/Cas9基因敲除原理及实验建议   CRISPR Cas9已经成为了最受欢迎的基因编辑技术之一,在2016年的国自然基金中也有很多项目是关于 CRISPR Cas9的.目前在市场上已经有 ...

  9. redis 缓存用户账单策略

    最近项目要求分页展示用户账单列表,为提高响应使用redis做缓存,用到的缓存策略和大家分享一下. 需求描述:展示用户账单基本信息以时间倒序排序,筛选条件账单类型(所有,订单收入.提现.充值...). ...

  10. CodeForces 682B Alyona and Mex (题意水题)

    题意:给定一个序列,你可以对这里面的数用小于它的数来代替,最后让你求,改完后的最大的序列中缺少的最小的数. 析:这个题,读了两个多小时也没读懂,要是读懂了,肯定能做出来...没什么可说的,就是尽量凑1 ...