zoukankan      html  css  js  c++  java
  • bzoj 3879 SvT

    LINK:SvT

    给出一个字符串 给出若干个后缀 求两两后缀之间的LCP.

    考虑SAM 要把字符串反着建立SAM 考虑两个后缀的LCP 其实就是在parent树上两点的LCA的长度.

    可以发现建立出虚树 在虚树上跑一遍dp即可。复杂度询问数*log.

    考虑SA 直接求出SA 按照各个后缀的排名排序加入对答案的贡献中 利用单调队列来维护新加入的后缀和之前的后缀的LCP 即可O(1)计算答案.

    不过需要ST表查两个后缀之间的LCP.

    代码复杂度的话 两者差不多 SAM还是要简单一些的 所以这里考虑写SA /cy.

    const int MAXN=500010<<1;
    int n,m,Q,top;
    char a[MAXN];
    int f[MAXN][21],b[MAXN*3],Log[MAXN],s[MAXN],w[MAXN];
    int x[MAXN],y[MAXN],h[MAXN],c[MAXN],sa[MAXN],rk[MAXN];
    inline void SA()
    {
    	m=150;
    	rep(1,n,i)++c[x[i]=a[i]];
    	rep(1,m,i)c[i]+=c[i-1];
    	rep(1,n,i)sa[c[x[i]]--]=i;
    	for(int k=1;k<=n;k=k<<1)
    	{
    		int num=0;
    		rep(n-k+1,n,i)y[++num]=i;
    		rep(1,n,i)if(sa[i]>k)y[++num]=sa[i]-k;
    		rep(1,m,i)c[i]=0;
    		rep(1,n,i)++c[x[i]];
    		rep(1,m,i)c[i]+=c[i-1];
    		fep(n,1,i)sa[c[x[y[i]]]--]=y[i];
    		rep(1,n,i)y[i]=x[i],x[i]=0;
    		x[sa[1]]=num=1;
    		rep(2,n,i)x[sa[i]]=y[sa[i]]==y[sa[i-1]]&&y[sa[i]+k]==y[sa[i-1]+k]?num:++num;
    		if(num==n)break;
    		m=num;
    	}
    	rep(1,n,i)rk[sa[i]]=i;
    }
    inline int cmp(int x,int y){return rk[x]<rk[y];}
    inline void get_Height()
    {
    	int k=0;
    	rep(1,n,i)
    	{
    		if(rk[i]==1)continue;
    		if(k)--k;
    		int j=sa[rk[i]-1];
    		while(a[i+k]==a[j+k])++k;
    		h[rk[i]]=k;
    	}
    }
    inline int LCP(int x,int y)
    {
    	x=rk[x];y=rk[y];
    	--y;int w=Log[y-x+1];
    	return min(f[x][w],f[y-(1<<w)+1][w]);
    }
    int main()
    {
    	freopen("1.in","r",stdin);
    	gt(n);gt(Q);gc(a);
    	SA();get_Height();
    	rep(2,n,i)
    	{
    		f[i-1][0]=h[i];
    		Log[i]=Log[i>>1]+1;
    	}
    	rep(1,Log[n-1],j)
    		rep(1,n-(1<<j),i)f[i][j]=min(f[i][j-1],f[i+(1<<(j-1))][j-1]);
    	rep(1,Q,i)
    	{
    		int get(x);ll cnt=0,ans=0,last=0;
    		rep(1,x,j)get(b[j]);
    		sort(b+1,b+1+x,cmp);
    		top=0;last=b[1];
    		rep(2,x,j)
    		{
    			if(b[j]==b[j-1])continue;
    			int len=LCP(last,b[j]),num=1;
    			while(top&&len<=s[top])
    			{
    				cnt-=(ll)s[top]*w[top];
    				num+=w[top];--top;
    			}
    			s[++top]=len;cnt+=(ll)num*len;
    			w[top]=num;ans+=cnt;last=b[j];
    		}
    		putl(ans);
    	}
    	return 0;
    }
    
  • 相关阅读:
    SVN服务器搭建(一)
    排序算法二:冒泡排序
    【LeetCode】136. Single Number
    【LeetCode】217. Contains Duplicate
    【LeetCode】189. Rotate Array
    【LeetCode】122. Best Time to Buy and Sell Stock II
    【LeetCode】26. Remove Duplicates from Sorted Array
    【LeetCode】20. Valid Parentheses
    【LeetCode】680. Valid Palindrome II
    【LeetCode】345. Reverse Vowels of a String
  • 原文地址:https://www.cnblogs.com/chdy/p/12599407.html
Copyright © 2011-2022 走看看