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;
    }
    
  • 相关阅读:
    Centos 设置默认路由得优先级
    openstack-NUMA排错记录
    openstack -新建project
    As3 常用日期工具
    As3 计算两个日期之间的天数差
    解决Asp.net Mvc返回JsonResult中DateTime类型数据格式的问题
    网盘+SVN
    SQL 并发-转
    工作目录
    Cookie
  • 原文地址:https://www.cnblogs.com/chdy/p/12599407.html
Copyright © 2011-2022 走看看