题面

传送门

题解

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

那么我们来考虑一下\(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. 使用opencv-python画OpenCV LOGO

    OpenCV2-Python 官方教程的练习 代码: #-*- coding:utf-8 -*- import numpy as np import cv2 img = np.zeros((512, ...

  2. O(n)求中位数和第k大数

    解题关键:模板与思路.面试题 #include<cstdio> #include<cstring> #include<algorithm> #include< ...

  3. php魔术方法__SET __GET

    __SET  设置一个不可访问的属性的时候 调用_set方法 __GET 获取一个不可访问的属性的时候  调用_get 方法 <?php class stu{ private $a; priva ...

  4. opencv cv::imageshow 不加waitKey()不能显示图片

    官方解释是highgui 没有给imshow绘制处理的时间.需要在imshow添加waitKey() waitKey()单位是ms

  5. code1074 食物链

    开3*n的并查集,其中x用来连接与x同类的,x+n用来连接x吃的,x+2*n用来连接x被吃的. 1 x y时,如果 x吃y 或 x被y吃,那么为假话, 否则x与y同类,x吃的y也吃,x被吃的y也被吃: ...

  6. Mac Sublime 相关资源

    MAC上安装并破解最新SublimeText3103版本 http://blog.csdn.net/yanzi1225627/article/details/50703942 Mac版的Sublime ...

  7. VMware 桥接模式 复制物理网络连接状态的作用

    参考: https://docs.vmware.com/cn/VMware-Workstation-Pro/15.0/com.vmware.ws.using.doc/GUID-826323AD-D01 ...

  8. Oracle VirtualBox 问题汇总

    1.打开虚拟机时报硬盘UUID 已经存在:错误信息: Cannot register the hard disk 'F:\VirtualBox VMs\cl-11r2-rac2\cl-11r2-rac ...

  9. Perl 学习笔记-高级控制结构

    1.unless控制结构 类似于独立的else语句; 要么条件为真, 要么执行语句块内的代码;  unless(<condition>){code...;} 等价于  if(<con ...

  10. [GO]多任务的资源竞争问题

    package main import ( "fmt" "time" ) func Printer(s string) { for _, data := ran ...