zoukankan      html  css  js  c++  java
  • 【BZOJ3413】匹配 离线+后缀树+树状数组

    【BZOJ3413】匹配

    Description

    Input

        第一行包含一个整数n(≤100000)。

        第二行是长度为n的由0到9组成的字符串。

        第三行是一个整数m。

        接下来m≤5·10行,第i行是一个由0到9组成的字符串s,保证单行字符串长度小于等于10^5,所有字符串长度和小于等于3·10^6

    Output

     输出m行,第i行表示第si和S匹配所比较的次数。

    Sample Input

    7
    1090901
    4
    87650
    0901
    109
    090

    Sample Output

    7
    10
    3
    4

    题解:题目是问你截止到匹配之前,A串的每个位置与B串的LCP+1之和。这要利用到一个性质,两个后缀的lcp长度等于后缀树上两个点的lca的mx值。所以我们对A串的反串建立后缀自动机,得到后缀树,然后将B串放到后缀树中进行匹配(后缀树中匹配不同于后缀自动机中的匹配,实现比较复杂,方法也有很多,可以看代码)。如果没有成功匹配,则我们取最后一个成功匹配的节点,从这个点沿着到根的路径一路走上去跑一个树形DP即可。如果匹配成功,我们记录一下匹配成功的节点以及匹配位置,然后离线处理。我们将原串中的点一个一个加到后缀树中去,用树状数组维护DFS序得到子树和,处理询问时依旧跑类似于树形DP的东西即可。

    #include <cstdio>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    #include <vector>
    using namespace std;
    typedef long long ll;
    const int N=200010;
    
    int n,m,tot,last,cnt;
    char S[N],T[N];
    int ch[N][10],mx[N],pre[N],p1[N],p2[N],mn[N],pos[N],qos[N],len[N],s[N],L[N],R[N],son[N][10],siz[N];
    vector<int> q[N];
    vector<int>::iterator it;
    int f[N];
    ll ans[N];
    inline int extend(int x)
    {
    	int p=last,np=++tot;	last=np;
    	mx[np]=mx[p]+1,siz[np]=1;
    	for(;p&&!ch[p][x];p=pre[p])	ch[p][x]=np;
    	if(!p)	ch[1][x]=np,pre[np]=1;
    	else
    	{
    		int q=ch[p][x];
    		if(mx[q]==mx[p]+1)	pre[np]=q;
    		else
    		{
    			int nq=++tot;	mx[nq]=mx[p]+1,R[nq]=R[q]-(mx[q]-mx[p]-1);
    			pre[nq]=pre[q],pre[np]=pre[q]=nq;
    			memcpy(ch[nq],ch[q],sizeof(ch[q]));
    			for(;p&&ch[p][x]==q;p=pre[p])	ch[p][x]=nq;
    		}
    	}
    	return np;
    }
    void dfs(int x)
    {
    	p1[x]=++p2[0];
    	for(int i=0,y;i<10;i++)	if((y=son[x][i]))	dfs(y),siz[x]+=siz[y],mn[x]=min(mn[x],mn[y]);
    	p2[x]=p2[0];
    }
    inline void updata(int x)
    {
    	for(int i=x;i<=tot;i+=i&-i)	s[i]++;
    }
    inline int query(int x)
    {
    	int ret=0,i;
    	for(i=x;i;i-=i&-i)	ret+=s[i];
    	return ret;
    }
    int main()
    {
    	scanf("%d%s",&n,S);
    	int i,j,x,y;
    	memset(mn,0x3f,sizeof(mn));
    	tot=last=1;
    	for(i=n-1;i>=0;i--)	pos[i]=extend(S[i]-'0'),mn[pos[i]]=i,R[pos[i]]=n-1;
    	for(i=2;i<=tot;i++)	L[i]=R[i]-(mx[i]-mx[pre[i]])+1,son[pre[i]][S[L[i]]-'0']=i;
    	scanf("%d",&m);
    	dfs(1);
    	R[1]=-1;
    	for(i=1;i<=m;i++)
    	{
    		scanf("%s",T),len[i]=strlen(T);
    		for(x=1,j=y=0;j<len[i];j++)
    		{
    			if(y<=R[x])
    			{
    				if(S[y]==T[j])	y++;
    				else	break;
    			}
    			else
    			{
    				if(son[x][T[j]-'0'])	x=son[x][T[j]-'0'],y=L[x]+1;
    				else	break;
    			}
    		}
    		qos[i]=x;
    		if(j<len[i])
    		{
    			if(x==1)	ans[i]=n;
    			else
    			{
    				ans[i]=n+1ll*siz[x]*min(mx[x]-mx[pre[x]],y-L[x]);
    				for(x=pre[x];x!=1;x=pre[x])	ans[i]+=1ll*(mx[x]-mx[pre[x]])*siz[x];
    			}
    		}
    		else
    		{
    			ans[i]=len[i]+mn[x];
    			if(mn[x])	q[mn[x]-1].push_back(i);
    		}
    	}
    	for(i=0;i<n;i++)
    	{
    		updata(p1[pos[i]]);
    		for(it=q[i].begin();it!=q[i].end();it++)
    		{
    			for(j=pre[qos[*it]];j;j=pre[j])	ans[*it]+=1ll*(mx[j]-mx[pre[j]])*(query(p2[j])-query(p1[j]-1));
    		}
    	}
    	for(i=1;i<=m;i++)	printf("%lld
    ",ans[i]);
    	return 0;
    }
  • 相关阅读:
    当再多大公司慢慢的放弃微软的技术时, 不知大家怎想?
    【叶子函数分享五十四】汉字转拼音函数 [转]
    java_easyui体系之DataGrid(4)[转]
    java_easyui体系之DataGrid(3)[转]
    java_easyui体系之DataGrid(2)[转]
    java_easyui体系之DataGrid(1)[转]
    java_easyui体系之目录 [转]
    Java 并发和多线程(三) 多线程的代价 [转]
    Java 并发和多线程(二) 多线程的优点 [转]
    Java 并发和多线程(一) Java并发性和多线程介绍[转]
  • 原文地址:https://www.cnblogs.com/CQzhangyu/p/8157460.html
Copyright © 2011-2022 走看看