zoukankan      html  css  js  c++  java
  • 【BZOJ4556】[Tjoi2016&Heoi2016]字符串 后缀数组+二分+主席树+RMQ

    【BZOJ4556】[Tjoi2016&Heoi2016]字符串

    Description

    佳媛姐姐过生日的时候,她的小伙伴从某东上买了一个生日礼物。生日礼物放在一个神奇的箱子中。箱子外边写了一个长为n的字符串s,和m个问题。佳媛姐姐必须正确回答这m个问题,才能打开箱子拿到礼物,升职加薪,出任CEO,嫁给高富帅,走上人生巅峰。每个问题均有a,b,c,d四个参数,问你子串s[a..b]的所有子串和s[c..d]的最长公共前缀的长度的最大值是多少?佳媛姐姐并不擅长做这样的问题,所以她向你求助,你该如何帮助她呢?

    Input

    输入的第一行有两个正整数n,m,分别表示字符串的长度和询问的个数。接下来一行是一个长为n的字符串。接下来m行,每行有4个数a,b,c,d,表示询问s[a..b]的所有子串和s[c..d]的最长公共前缀的最大值。1<=n,m<=100,000,字符串中仅有小写英文字母,a<=b,c<=d,1<=a,b,c,d<=n

    Output

     对于每一次询问,输出答案。

    Sample Input

    5 5
    aaaaa
    1 1 1 5
    1 5 1 1
    2 3 2 3
    2 4 2 3
    2 3 2 4

    Sample Output

    1
    1
    2
    2
    2

    题解:先求后缀数组,我们找到[c..d]的rank值,如果不考虑b和d的影响(即我们求的是两个后缀LCP),那么显然最优的a的rank值一定是c的前驱或者后继。那么如何求一段区间中,rank值的前驱或后继呢?用可持久化线段树维护,再用RMQ求LCP即可。

    但是题中给出的后缀是有长度限制的(即子串),怎么办?二分答案!我们只求[a,b-mid+1]这段中的前驱后继,用这个来更新答案,就不用考虑长度限制了。

     

    #include <cstdio>
    #include <cstring>
    #include <iostream>
    
    const int maxn=100010;
    using namespace std;
    int n,Q,m,tot,ans;
    int r[maxn],ra[maxn],rb[maxn],sa[maxn],st[maxn],rank[maxn],h[maxn],f[18][maxn],Log[maxn],rt[maxn];
    struct sag
    {
    	int ls,rs,siz;
    }s[maxn*30];
    char str[maxn];
    inline void build()
    {
    	int i,j,*x=ra,*y=rb,k,p;
    	for(i=0;i<n;i++)	st[x[i]=r[i]]++;
    	for(i=1;i<m;i++)	st[i]+=st[i-1];
    	for(i=n-1;i>=0;i--)	sa[--st[x[i]]]=i;
    	for(j=p=1;p<n;j<<=1,m=p)
    	{
    		for(p=0,i=n-j;i<n;i++)	y[p++]=i;
    		for(i=0;i<n;i++)	if(sa[i]>=j)	y[p++]=sa[i]-j;
    		for(i=0;i<m;i++)	st[i]=0;
    		for(i=0;i<n;i++)	st[x[y[i]]]++;
    		for(i=1;i<m;i++)	st[i]+=st[i-1];
    		for(i=n-1;i>=0;i--)	sa[--st[x[y[i]]]]=y[i];
    		for(i=p=1,swap(x,y),x[sa[0]]=0;i<n;i++)
    			x[sa[i]]=(y[sa[i]]==y[sa[i-1]]&&y[sa[i]+j]==y[sa[i-1]+j])?p-1:p++;
    	}
    	for(i=1;i<n;i++)	rank[sa[i]]=i;
    	for(i=k=0;i<n-1;h[rank[i++]]=k)
    		for(k?k--:0,j=sa[rank[i]-1];r[i+k]==r[j+k];k++);
    	for(i=1;i<n;i++)	f[0][i]=h[i];
    	for(i=2;i<=n;i++)	Log[i]=Log[i>>1]+1;
    	for(j=1;(1<<j)<n;j++)	for(i=1;i+(1<<j)-1<n;i++)	f[j][i]=min(f[j-1][i],f[j-1][i+(1<<(j-1))]);
    }
    void insert(int x,int &y,int l,int r,int a)
    {
    	y=++tot,s[y].siz=s[x].siz+1;
    	if(l==r)	return ;
    	int mid=(l+r)>>1;
    	if(a<=mid)	s[y].rs=s[x].rs,insert(s[x].ls,s[y].ls,l,mid,a);
    	else	s[y].ls=s[x].ls,insert(s[x].rs,s[y].rs,mid+1,r,a);
    }
    int getrank(int l,int r,int x,int y,int a)
    {
    	if(l==r)	return s[y].siz-s[x].siz;
    	int mid=(l+r)>>1;
    	if(a<=mid)	return getrank(l,mid,s[x].ls,s[y].ls,a);
    	else	return s[s[y].ls].siz-s[s[x].ls].siz+getrank(mid+1,r,s[x].rs,s[y].rs,a);
    }
    int find(int l,int r,int x,int y,int a)
    {
    	if(a>s[y].siz-s[x].siz)	return -1;
    	if(l==r)	return l;
    	int mid=(l+r)>>1;
    	if(a<=s[s[y].ls].siz-s[s[x].ls].siz)	return find(l,mid,s[x].ls,s[y].ls,a);
    	return find(mid+1,r,s[x].rs,s[y].rs,a-s[s[y].ls].siz+s[s[x].ls].siz);
    }
    inline int query(int a,int b)
    {
    	if(a==-1)	return 0;
    	if(a==b)	return n-sa[a];
    	if(a>b)	swap(a,b);
    	a++;
    	int k=Log[b-a+1];
    	return min(f[k][a],f[k][b-(1<<k)+1]);
    }
    inline int rd()
    {
    	int ret=0,f=1;	char gc=getchar();
    	while(gc<'0'||gc>'9')	{if(gc=='-')	f=-f;	gc=getchar();}
    	while(gc>='0'&&gc<='9')	ret=ret*10+gc-'0',gc=getchar();
    	return ret*f;
    }
    inline bool check(int a,int b,int c,int len)
    {
    	int x=getrank(0,n,rt[a],rt[b+1],c);
    	if(query(find(0,n,rt[a],rt[b+1],x),c)>=len)	return 1;
    	if(query(find(0,n,rt[a],rt[b+1],x+1),c)>=len)	return 1;
    	return 0;
    }
    int main()
    {
    	n=rd(),Q=rd();
    	int i,a,b,c,d;
    	scanf("%s",str);
    	for(i=0;i<n;i++)	r[i]=str[i]-'a'+1,m=max(m,r[i]+1);
    	n++,build(),n--;
    	for(i=0;i<n;i++)	insert(rt[i],rt[i+1],0,n,rank[i]);
    	for(i=1;i<=Q;i++)
    	{
    		a=rd()-1,b=rd()-1,c=rd()-1,d=rd()-1;
    		int l=0,r=min(d-c,b-a)+2,mid;
    		while(l<r)
    		{
    			mid=(l+r)>>1;
    			if(check(a,b-mid+1,rank[c],mid))	l=mid+1;
    			else	r=mid;
    		}
    		printf("%d
    ",l-1);
    	}
    	return 0;
    }//5 5 aaaaa 1 1 1 5 1 5 1 1 2 3 2 3 2 4 2 3 2 3 2 4

     

  • 相关阅读:
    引擎优化笔记3
    IP/TCP/UDP checsum
    引擎优化笔记2
    Hive Map结构
    clickhouse概述
    Hive小文件合并
    hive计算引擎~Tez
    Hive优化~参数优化
    Hive分析窗口函数(三) CUME_DIST,PERCENT_RANK
    HIve实现数据抽样
  • 原文地址:https://www.cnblogs.com/CQzhangyu/p/7859551.html
Copyright © 2011-2022 走看看