zoukankan      html  css  js  c++  java
  • bzoj 5084 hashit

    LINK:hashit

    动态在末尾删除一个节点或者加入一个节点 求每次操作过后本质不同的子串的个数。

    显然我们可以离线,当然我们发现删除末尾的节点也是比较困难的 可以选择不删而是返回到last.

    发现这样做其实是一颗trie树 我们建立广义SAM.

    每次加入节点 其实是parent树上一堆链的并的答案。(不明白可以画一下样例的图即可。

    我们将操作离线后使用常规set维护dfs序解决。

    const int MAXN=200010;
    int n,cnt=1,last=1,v,len;
    struct wy
    {
    	int fa,len;
    	int ch[26];
    }t[MAXN];
    int f[MAXN][20],d[MAXN],Log[MAXN],pre[MAXN],dfn[MAXN],pos[MAXN];
    int lin[MAXN],ver[MAXN],nex[MAXN];
    char a[MAXN];
    set<int>s;
    set<int>::iterator it;
    inline void add(int x,int y)
    {
    	ver[++len]=y;
    	nex[len]=lin[x];
    	lin[x]=len;
    }
    inline int insert(int x)
    {
    	int p=last;
    	if(t[p].ch[x])
    	{
    		int q=t[p].ch[x];
    		if(len(q)==len(p)+1)return last=q;
    		int nq=++cnt;
    		t[nq]=t[q];
    		f(q)=nq;
    		len(nq)=len(p)+1;
    		while(p&&t[p].ch[x]==q)
    		{
    			t[p].ch[x]=nq;
    			p=f(p);
    		}
    		return last=nq;
    	}
    	int np=last=++cnt;
    	len(np)=len(p)+1;
    	while(p&&!t[p].ch[x])
    	{
    		t[p].ch[x]=np;
    		p=f(p);
    	}
    	if(!p)f(np)=1;
    	else
    	{
    		int q=t[p].ch[x];
    		if(len(q)==len(p)+1)f(np)=q;
    		else 
    		{
    			int nq=++cnt;
    			t[nq]=t[q];
    			f(q)=f(np)=nq;
    			len(nq)=len(p)+1;
    			while(p&&t[p].ch[x]==q)
    			{
    				t[p].ch[x]=nq;
    				p=f(p);
    			}
    		}
    	}
    	return last;
    }
    inline void dfs(int x,int father)
    {
    	f[x][0]=father;d[x]=d[father]+1;dfn[x]=++v;pos[v]=x;
    	rep(1,Log[d[x]],i)f[x][i]=f[f[x][i-1]][i-1];
    	go(x)dfs(tn,x);return;
    }
    inline int LCA(int x,int y)
    {
    	if(d[x]<d[y])swap(x,y);
    	for(int i=Log[d[x]];i>=0;--i)
    		if(d[f[x][i]]>=d[y])x=f[x][i];
    	if(x==y)return x;
    	for(int i=Log[d[x]];i>=0;--i)
    		if(f[x][i]!=f[y][i])x=f[x][i],y=f[y][i];
    	return f[x][0];
    }
    int main()
    {
    	freopen("1.in","r",stdin);
    	gc(a);n=strlen(a+1);ll ans=0;
    	rep(1,n,i)
    	{
    		if(a[i]=='-')last=pre[last];
    		else
    		{
    			int w=last;
    			insert(a[i]-'a');pre[last]=w;
    		}
    	}
    	rep(2,cnt,i)add(f(i),i),Log[i]=Log[i>>1]+1;
    	dfs(1,0);int now=1;
    	for(int i=1;i<=n;++i)
    	{
    		if(a[i]=='-')
    		{
    			ans-=len(now);it=s.find(dfn[now]);
    			int x=0,y=0;++it;
    			if(it!=s.end())x=pos[*it];
    			--it;
    			if(it!=s.begin())y=pos[*--it];
    			if(x)ans+=len(LCA(x,now));
    			if(y)ans+=len(LCA(y,now));
    			if(x&&y)ans-=len(LCA(x,y));
    			s.erase(dfn[now]);now=pre[now];
    		}
    		else
    		{
    			now=t[now].ch[a[i]-'a'];ans+=len(now);
    			it=s.upper_bound(dfn[now]);
    			int x=0,y=0;
    			if(it!=s.end())y=pos[*it];
    			if(it!=s.begin())x=pos[*--it];
    			if(x)ans-=len(LCA(x,now));
    			if(y)ans-=len(LCA(y,now));
    			if(x&&y)ans+=len(LCA(x,y));
    			s.insert(dfn[now]);
    		}
    		put(ans);
    	}
    	return 0;
    }
    
  • 相关阅读:
    数组
    JavaScript语法
    Math.random()
    第二第三周暑期集训总结
    第一周
    ACM课程学习总结
    专题四---总结
    专题四--1004
    专题四--1005
    专题四--1006
  • 原文地址:https://www.cnblogs.com/chdy/p/12558495.html
Copyright © 2011-2022 走看看