• bzoj 5084: hashit


    Description

    你有一个字符串S,一开始为空串,要求支持两种操作
    在S后面加入字母C
    删除S最后一个字母
    问每次操作后S有多少个两两不同的连续子串

    Solution

    先忽略删除操作,建出最终的串的 (SAM),构建过程的所有可能的串的 (SAM) 都包括在这里面
    要维护 (sum len[x]-len[fa[x]])
    考虑插入一个结点会产生的贡献,因为每一条边只会贡献一次,所以需要容斥减掉一些贡献
    那么需要考虑已经被加入的结点中与这个点 (dfs) 序相邻的,他们的 (lca) 以上的部分需要被减去
    取与两个相邻节点的 (lca) 中深度较大的一个减去贡献,或者容斥一下
    (set) 维护一下 (dfs)

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const int N=2e5+10;
    char s[N];int cur=1,cnt=1,fa[N],len[N],ch[N][26],pos[N],FA[N][21],b[N],dep[N];
    int n,st[N],tp=0,head[N],Head[N],nxt[N*4],to[N*4],num=0,la[N],dfn[N],DFN=0;
    set<int>v;set<int>::iterator it,wt;
    inline void link(int x,int y){nxt[++num]=head[x];to[num]=y;head[x]=num;}
    inline void Link(int x,int y){nxt[++num]=Head[x];to[num]=y;Head[x]=num;}
    inline void ins(int p,int c){
    	cur=++cnt;len[cur]=len[p]+1;
    	for(;p && !ch[p][c];p=fa[p])ch[p][c]=cur;
    	if(!p)fa[cur]=1;
    	else{
    		int q=ch[p][c];
    		if(len[p]+1==len[q])fa[cur]=q;
    		else{
    			int nt=++cnt;len[nt]=len[p]+1;
    			memcpy(ch[nt],ch[q],sizeof(ch[nt]));
    			fa[nt]=fa[q];fa[cur]=fa[q]=nt;
    			for(;p && ch[p][c]==q;p=fa[p])ch[p][c]=nt;
    		}
    	}
    }
    inline void bfs(){
    	queue<int>Q;
    	for(int i=head[0];i;i=nxt[i])Q.push(to[i]),la[to[i]]=1;
    	while(!Q.empty()){
    		int x=Q.front();Q.pop();
    		ins(la[x],s[x]-'a');pos[x]=cur;
    		for(int i=head[x];i;i=nxt[i])
    			Q.push(to[i]),la[to[i]]=cur;
    	}
    }
    inline void dfs(int x){
    	b[dfn[x]=++DFN]=x;
    	for(int i=1;i<=20;i++)FA[x][i]=FA[FA[x][i-1]][i-1];
    	for(int i=Head[x];i;i=nxt[i])dep[to[i]]=dep[x]+1,FA[to[i]][0]=x,dfs(to[i]);
    }
    inline int lca(int x,int y){
    	if(dep[x]<dep[y])swap(x,y);
    	int deep=dep[x]-dep[y];
    	for(int i=20;i>=0;i--)if(deep>>i&1)x=FA[x][i];
    	if(x==y)return x;
    	for(int i=20;i>=0;i--)if(FA[x][i]!=FA[y][i])x=FA[x][i],y=FA[y][i];
    	return FA[x][0];
    }
    ll ans=0;
    inline void Modify(int x,int o){
    	if(o==1)v.insert(x);
    	it=wt=v.find(x);
    	ans+=o*len[b[x]];
    	if(wt!=v.begin())--wt,ans-=o*len[lca(b[*wt],b[x])];
    	if(it!=--v.end())++it,ans-=o*len[lca(b[*it],b[x])];
    	if(*it!=x && *wt!=x)ans+=o*len[lca(b[*it],b[*wt])];
    	if(o==-1)v.erase(x);
    }
    int main(){
    	freopen("C.in","r",stdin);
    	freopen("C.out","w",stdout);
    	scanf("%s",s+1);n=strlen(s+1);
    	for(int i=1;i<=n;i++){
    		if(s[i]=='-')tp--;
    		else link(st[tp],i),st[++tp]=i;
    	}
    	bfs();
    	for(int i=1;i<=cnt;i++)Link(fa[i],i);
    	dfs(1);tp=0;
    	for(int i=1;i<=n;i++){
    		if(s[i]=='-')Modify(dfn[pos[st[tp--]]],-1);
    		else Modify(dfn[pos[st[++tp]=i]],1);
    		printf("%lld
    ",ans);
    	}
    	return 0;
    }
    
    
  • 相关阅读:
    Android读取url图片保存及文件读取
    Adroid解析json
    接口设计的 11 种原则
    检查并创建目录mkdir
    python 替换windows换行符为unix格式
    python中 __name__及__main()__的使用
    python中的urlencode与urldecode
    CentOS Docker 安装
    CentOS基础命令大全
    ubuntu更换阿里源
  • 原文地址:https://www.cnblogs.com/Yuzao/p/9057854.html
Copyright © 2020-2023  润新知