BZOJ5084: hashit

BZOJ5084: hashit

https://lydsy.com/JudgeOnline/problem.php?id=5084

分析:

  • \(trie\)建立广义后缀自动机,由于是\(trie\),不会有多余结点(lenx==lenfa)
  • 令后缀自动机结点权值为\(len_x-len _ {fa_x}\)
  • 每次询问时答案就等于所有结点到根的树链的并的权值和。
  • 每次是插入一个点,删除一个点,用\(set\)动态维护即可。

代码:

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cstdlib>
#include <cmath>
#include <iostream>
#include <set>
using namespace std;
typedef long long ll;
#define N 100050
#define db(x) cerr<<#x<<" = "<<x<<endl
char opt[N];
int n;
struct Trie {
	int ch[N][26],cnt,fa[N];
	void init() {cnt=1;}
	void Wk() {
		init();
		int i,p=1;
		for(i=1;i<=n;i++) {
			if(opt[i]=='-') {
				p=fa[p];
			}else {
				int &q=ch[p][opt[i]-'a'];
				if(!q) q=++cnt,fa[q]=p;
				p=q;
			}
		}
	}
}t1;
struct Sam {
	#undef N 
	#define N 200050
	int ch[N][26],fa[N],len[N],cnt,Q[N],Lst[N];
	int ke[N],ro[N],f[20][N],Lg[N],dep[N],w[N];
	ll dis[N];
	int head[N],to[N],nxt[N],tot,dfn[N];
	inline void add(int u,int v) {
		to[++tot]=v; nxt[tot]=head[u]; head[u]=tot;
	}
	void dfs(int x) {
		int i; dfn[x]=++dfn[0];
		for(i=head[x];i;i=nxt[i]) {
			dep[to[i]]=dep[x]+1; 
			w[to[i]]=len[to[i]]-len[x];
			dis[to[i]]=dis[x]+w[to[i]];
			dfs(to[i]);
		}
	}
	void init() {cnt=1;}
	int insert(int x,int lst) {
		int p=lst,np=++cnt,q,nq;
		len[np]=len[p]+1; lst=np;
		for(;p&&!ch[p][x];p=fa[p]) ch[p][x]=np;
		if(!p) fa[np]=1;
		else {
			q=ch[p][x];
			if(len[q]==len[p]+1) fa[np]=q;
			else {
				nq=++cnt; 
				len[nq]=len[p]+1; fa[nq]=fa[q]; memcpy(ch[nq],ch[q],sizeof(ch[q]));
				fa[np]=fa[q]=nq;
				for(;p&&ch[p][x]==q;p=fa[p]) ch[p][x]=nq;
			}
		}return lst;
	}
	int lca(int x,int y) {
		int i;
		if(dep[x]<dep[y]) swap(x,y);
		for(i=Lg[dep[x]];i>=0;i--) {
			if(dep[f[i][x]]>=dep[y]) x=f[i][x];
		}if(x==y) return x;
		for(i=Lg[dep[x]];i>=0;i--) {
			if(f[i][x]!=f[i][y]) x=f[i][x],y=f[i][y];
		}return f[0][x];
	}
	struct A {
		int x,v;
		bool operator < (const A &u) const {return v<u.v;}
	};
	set<A>S;
	set<A>::iterator it;
	ll nowans;
	void fadd(int p) {
		A t=(A){p,dfn[p]};
		nowans+=dis[p];
		it=S.upper_bound(t);
		int x=0,y=0;
		if(it!=S.end()) {
			y=it->x;
		}
		if(it!=S.begin()) {
			it--;
			x=it->x;
		}
		if(x) nowans-=dis[lca(x,p)];
		if(y) nowans-=dis[lca(y,p)];
		if(x&&y) nowans+=dis[lca(x,y)];
		S.insert(t);
	}
	void fdel(int p) {
		A t=(A){p,dfn[p]};
		S.erase(t);
		nowans-=dis[p];
		it=S.upper_bound(t);
		int x=0,y=0;
		if(it!=S.end()) {
			y=it->x;
		}
		if(it!=S.begin()) {
			it--;
			x=it->x;
		}
		if(x) nowans+=dis[lca(x,p)];
		if(y) nowans+=dis[lca(y,p)];
		if(x&&y) nowans-=dis[lca(x,y)];
	}
	void Wk() {
		init();
		int p,i,j;
		int l=0,r=0;
		Q[r++]=1; Lst[1]=1;
		while(l<r) {
			p=Q[l++];
			for(i=0;i<26;i++) if(t1.ch[p][i]) {
				int q=t1.ch[p][i];
				Lst[q]=insert(i,Lst[p]);
				Q[r++]=q;
			}
		}
		Lg[0]=-1;
		for(i=1;i<=cnt;i++) f[0][i]=fa[i],Lg[i]=Lg[i>>1]+1;
		for(i=1;(1<<i)<=cnt;i++) {
			for(j=1;j<=cnt;j++) f[i][j]=f[i-1][f[i-1][j]];
		}
		for(i=2;i<=cnt;i++) add(fa[i],i);
		dfs(1);
		p=1;
		for(i=1;i<=n;i++) {
			if(opt[i]=='-') {
				fdel(Lst[p]);
				p=t1.fa[p];
				printf("%lld\n",nowans);
			}else {
				p=t1.ch[p][opt[i]-'a'];
				fadd(Lst[p]);
				printf("%lld\n",nowans);
			}
		}
	}
}t2;
int main() {
	scanf("%s",opt+1);
	n=strlen(opt+1);
	t1.Wk();
	t2.Wk();
}
posted @ 2019-01-01 20:18  fcwww  阅读(310)  评论(0编辑  收藏  举报