http://1572m36l09.iask.in:30808/problem/113
题目描述
你需要实现一种数据结构(可以参考标题)来实现以下操作:
为了证明你进行了这些操作,每一次操作后,你需要输出当前字符串的不同子串个数以及在之前任意一个字符串中出现过的不同的字符串个数。
输入格式
一行一个长度为n字符串S。对于第k位,若Sk是一个小写英文字符,表示在当前串的末尾插入Sk。若是-
,则表示删除末尾的字符。
输出格式
共n行,每行两个正整数,意义如题目描述所示。
对于100%的数据,n≤200000,保证任何时候字符串的长度非负
先建出trie树,用bfs建出trie的SAM(dfs复杂度不对),具体就是加入trie上某个点之前把last置为父节点的last。trie上每个节点对应SAM上的一个点就是它的last(与SAM求子串出现次数类似)。
第一问就是求trie上一个点到根的链上所有点在parent树上的链并,用dfs序+set解决。
第二问就是当前已访问过的所有点在parent树上的链并。
#include<cstdio> #include<cstring> #include<cmath> #include<algorithm> #include<vector> #include<set> using namespace std; const int N=200005; struct node { int ch[26],fa,len; }a[N*2]; int n,i,j,k,lst,cnt,w,ch[N][26],fa[N],Lst[N],num,q[2*N],bg,ed,head[2*N],adj[2*N],nxt[2*N],pt1[N],pt2[N],dep[N*2],d[N*2][20],h[N*2],id[N*2]; long long ans1[N],ans2[N],g[N],dis[N*2],ans,ANS; char s[N]; set<int> st,ST; set<int>::iterator ddq; bool v[N*2]; inline void Clear(int id) { a[id].fa=a[id].len=0; memset(a[id].ch,0,sizeof(a[id].ch)); } void dfs(int x) { h[++i]=x; id[x]=i; dis[x]+=a[x].len-a[a[x].fa].len; for(int y=head[x];y;y=nxt[y]) { dep[adj[y]]=dep[x]+1; d[adj[y]][0]=x; dis[adj[y]]+=dis[x]; dfs(adj[y]); } } int lca(int a,int b) { int c,y; if(dep[a]<dep[b]) swap(a,b); for(c=dep[a]-dep[b],y=0;c;c>>=1,++y) if(c&1) a=d[a][y]; if(a==b) return a; for(c=19;c>=0;--c) if(d[a][c]!=d[b][c]) a=d[a][c],b=d[b][c]; return d[a][0]; } void add(int x) { int y=1,z=1; ddq=st.upper_bound(id[x]); if(ddq!=st.end()) y=lca(x,h[*ddq]); ddq--; z=lca(x,h[*ddq]); if(dep[z]>dep[y]) y=z; ans+=dis[x]-dis[y]; st.insert(id[x]); if(!v[x]) { v[x]=true; ddq=ST.upper_bound(id[x]); if(ddq!=ST.end()) y=lca(x,h[*ddq]); ddq--; z=lca(x,h[*ddq]); if(dep[z]>dep[y]) y=z; ANS+=dis[x]-dis[y]; ST.insert(id[x]); } } void del(int x) { st.erase(id[x]); int y=1,z=1; ddq=st.upper_bound(id[x]); if(ddq!=st.end()) y=lca(x,h[*ddq]); ddq--; z=lca(x,h[*ddq]); if(dep[z]>dep[y]) y=z; ans-=dis[x]-dis[y]; } int main() { freopen("c.in","r",stdin); freopen("c.out","w",stdout); scanf("%s",s+1); num=1; Lst[1]=1; lst=cnt=1; Clear(1); for(i=1,k=1;s[i];++i) { if(s[i]>='a'&&s[i]<='z') { j=s[i]-'a'; if(ch[k][j]) { k=ch[k][j]; continue; } ch[k][j]=++num; fa[num]=k; k=num; } else k=fa[k]; } for(i=0;i<26;++i) if(ch[1][i]) { q[++ed]=ch[1][i]; h[ed]=i; } bg=1; while(bg<=ed) { j=h[bg]; lst=Lst[fa[q[bg]]]; int p,np; p=lst; np=lst=++cnt; Clear(cnt); a[np].len=a[p].len+1; pt1[q[bg]]=np; for(;p&&!a[p].ch[j];p=a[p].fa) a[p].ch[j]=np; if(!p) a[np].fa=1; else { int q=a[p].ch[j]; if(a[q].len==a[p].len+1) a[np].fa=q; else { int nq=++cnt; Clear(cnt); a[nq]=a[q]; a[nq].len=a[p].len+1; //ans2[i]+=a[a[q].fa].len-a[nq].len; //ans2[i]+=a[nq].len-a[a[nq].fa].len; a[np].fa=a[q].fa=nq; for(;p&&a[p].ch[j]==q;p=a[p].fa) a[p].ch[j]=nq; } } Lst[q[bg]]=lst; //printf("%d\n",lst); for(i=0;i<26;++i) if(ch[q[bg]][i]) { q[++ed]=ch[q[bg]][i]; h[ed]=i; } ++bg; } for(i=2;i<=cnt;++i) { adj[i-1]=i; nxt[i-1]=head[a[i].fa]; head[a[i].fa]=i-1; //printf("%d %d\n",a[i].fa,i); } i=0; dfs(1); for(i=1;(1<<i)<cnt;++i) for(j=1;j<=cnt;++j) if(d[j][i-1]) d[j][i]=d[d[j][i-1]][i-1]; st.insert(1); ST.insert(1); for(i=1,k=1;s[i];++i) { if(s[i]>='a'&&s[i]<='z') { j=s[i]-'a'; k=ch[k][j]; add(pt1[k]); //if(pt2[k]) //add(pt2[k]); } else { del(pt1[k]); //if(pt2[k]) //del(pt2[k]); k=fa[k]; } ans1[i]=ans; ans2[i]=ANS; } for(i=1;s[i];++i) printf("%lld %lld\n",ans1[i],ans2[i]); return 0; }