题面

传送门

题解

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

那么我们来考虑一下\(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. Java CST格式字符串转换成Date类型的数据

    Date date = new SimpleDateFormat("EEE MMM dd HH:mm:ss zzz yyyy", Locale.US).parse("We ...

  2. Python——字典与字典方法

    字典是一种通过名字或者关键字引用的得数据结构,其键可以是数字.字符串.元组,这种结构类型也称之为映射.字典类型是Python中唯一內建的映射类型,基本的操作包括如下: (1)len():返回字典中键— ...

  3. Mac shell使用技巧总结(转)

    1.文件操作 常用目录 /Systme/Library/Extensions // 驱动所在目录 /User/XXX/Desktop // 桌面目录 资源库 chflags nohidden ~/Li ...

  4. Mysql(Navicat for Mysql)怎么添加数据库

    1.首先打开Navicat for Mysql: 2.打开后界面如下图所示,双击连接localhost_3306: 3.连接后localhost_3306变成绿色,如下图所示: 4.选中下面任意数据库 ...

  5. 基于mosquitto的MQTT服务器---SSL/TLS 单向认证+双向认证

    基于mosquitto的MQTT服务器---SSL/TLS 单向认证+双向认证 摘自:https://blog.csdn.net/ty1121466568/article/details/811184 ...

  6. 跟我学习css3之transition

    HTML5和css3已经是将来的发展趋势,现在有很多移动端还有一些游戏公司已然使用它们开 发了比较成功的产品.我在2011年的时候也跟着技术潮流初浅的学习了html5+css3.毕竟那 时候我没有把学 ...

  7. NSArray去除重复元素

    直接上代码吧! 1.可以创建一个新的数组,对需要去除重复的数组进行遍历,如果新数组不包含就数组,那么添加元素,如果包含就不添加. NSMutableArray *array = [NSMutableA ...

  8. 20、Semantic-UI之数据验证

    20.1 实现数据验证   在很多前端框架中都提供了数据验证的操作,比如jQuery的验证框架等,但是jQuery的验证框架js文件太多:在使用Semantic-UI框架的时候只需要导入semanti ...

  9. VMware安装Ubuntu分辨率无法适应屏幕的解决方法

    ​ 一开始虚拟机安装Ubuntu的时候遇到分辨率无法适应屏幕的时候,百度了一大堆都说使用xrandr命令来修改分辨率,但是还是无法适应1920x1080的屏幕,强迫症表示非常难受! ​ 然后在不知道是 ...

  10. Backup--如何快速截断日志

    --在SQL Server 2005 中,可用使用 BACKUP LOG WITH TRUNCATE_ONLY来迅速清理日志,该命令在 SQL Server2008 及更高版本上被去除. --BACK ...