题面

传送门

题解

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

那么我们来考虑一下\(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算法 第七届 蓝桥杯B组(题+答案) 4.分小组

    4.分小组  (代码填空) 9名运动员参加比赛,需要分3组进行预赛.有哪些分组的方案呢? 我们标记运动员为 A,B,C,... I下面的程序列出了所有的分组方法. 该程序的正常输出为:ABC DEF ...

  2. cdoj1091-秋实大哥の恋爱物语 【kmp】

    http://acm.uestc.edu.cn/#/problem/show/1091 秋实大哥の恋爱物语 Time Limit: 5000/2000MS (Java/Others)     Memo ...

  3. 【POJ2151】Check the difficulty of problems

    题意 某场比赛有M道问题,T支队伍,和数字N给出每支队伍解决每道问题的概率. 问这场比赛满足下面两个条件的概率 1.每支队伍至少做出一道题 2.冠军队至少做出N道题. 分析 条件2是不是可以转化为 至 ...

  4. SQL Server的聚集索引和非聚集索引

    微软的SQL SERVER提供了两种索引:聚集索引(clustered index,也称聚类索引.簇集索引)和非聚集索引(nonclustered index,也称非聚类索引.非簇集索引)…… (一) ...

  5. 15-Call to your teacher(有向图的连通判断)

    链接:https://www.nowcoder.net/acm/contest/76/F来源:牛客网 时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C++ 32768K,其他语言65536K ...

  6. linux系统如何安装vmware Tools(下面以CentOS为例)

    VMwareTools是VMware虚拟机中很重要的一个工具包,有些时候在虚拟机中安装完操作系统会缺少网卡驱动,不能上网,这时只要安装VMwareTools就可以解决问题,下面以CentOS为例,来说 ...

  7. 用Redis解决互联网项目的数据读取难点

    Redis在很多方面与其他数据库解决方案不同:它使用内存提供主存储支持,而仅使用硬盘做持久性的存储:它的数据模型非常独特,用的是单线程.另一个大区别在于,你可以在开发环境中使用Redis的功能,但却不 ...

  8. p2944 [USACO09MAR]地震损失2Earthquake Damage 2

    传送门 分析 我们让s到1,关键点到t分别连流量为inf的边 于是我们可以考虑跑s到t的最小割 于是我们将所有点拆为两个点,关键点和1的两个点之间连inf,其余点连1 将原图的边也连上,流量为inf ...

  9. 王子和公主 UVa10635

    [题目描述]:王子和公主 一个王子和公主在n*n的格子中行走,这些格子是有1....n^2的编号的.现在给定p+1个数,再给定q+1个数,公主和王子可以选择其中某些格子行走,求他们最多能走几个相同的格 ...

  10. realsense pcl git

    https://github.com/Ext4FAT/Registration vc++ pcl realsense  矿泉水瓶子 https://github.com/dBeker/PCL-Real ...