【bzoj5084】 hashit(广义SAM+set)

题面

传送门

题解

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

那么我们来考虑一下\(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;
}
posted @ 2019-03-23 10:56  bztMinamoto  阅读(278)  评论(0编辑  收藏  举报
Live2D