【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\n",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

【BZOJ4556】[Tjoi2016&Heoi2016]字符串 后缀数组+二分+主席树+RMQ的更多相关文章

  1. bzoj4556: [Tjoi2016&Heoi2016]字符串 (后缀数组加主席树)

    题目是给出一个字符串,每次询问一个区间[a,b]中所有的子串和另一个区间[c,d]的lcp最大值,首先求出后缀数组,对于lcp的最大值肯定是rank[c]的前驱和后继,但是对于这个题会出现问题,就是题 ...

  2. [BZOJ4556][Tjoi2016&Heoi2016]字符串 后缀数组+主席树

    4556: [Tjoi2016&Heoi2016]字符串 Time Limit: 20 Sec  Memory Limit: 128 MB Description 佳媛姐姐过生日的时候,她的小 ...

  3. 【BZOJ-4556】字符串 后缀数组+二分+主席树 / 后缀自动机+线段树合并+二分

    4556: [Tjoi2016&Heoi2016]字符串 Time Limit: 20 Sec  Memory Limit: 128 MBSubmit: 657  Solved: 274[Su ...

  4. Bzoj4556: [Tjoi2016&Heoi2016]字符串 后缀数组

    4556: [Tjoi2016&Heoi2016]字符串 Time Limit: 20 Sec  Memory Limit: 128 MBSubmit: 169  Solved: 87[Sub ...

  5. BZOJ 4556 [Tjoi2016&Heoi2016]字符串 ——后缀数组 ST表 主席树 二分答案

    Solution 1: 后缀数组暴力大法好 #include <map> #include <cmath> #include <queue> #include &l ...

  6. [HEOI2016/TJOI2016]字符串(后缀数组+二分+主席树/后缀自动机+倍增+线段树合并)

    后缀数组解法: 先二分最长前缀长度 \(len\),然后从 \(rnk[c]\) 向左右二分 \(l\) 和 \(r\) 使 \([l,r]\) 的 \(height\geq len\),然后在主席树 ...

  7. BZOJ4556:[TJOI\HEOI2016]字符串(后缀数组,主席树,二分,ST表)

    Description 佳媛姐姐过生日的时候,她的小伙伴从某东上买了一个生日礼物.生日礼物放在一个神奇的箱子中.箱子外边写了一个长为n的字符串s,和m个问题.佳媛姐姐必须正确回答这m个问题,才能打开箱 ...

  8. bzoj 4556 [Tjoi2016&Heoi2016]字符串——后缀数组+主席树

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=4556 本来只要查 ht[ ] 数组上的前驱和后继就行,但有长度的限制.可以二分答案解决!然后 ...

  9. 【BZOJ4556】字符串(后缀数组,主席树)

    [BZOJ4556]字符串(后缀数组,主席树) 题面 BZOJ 题解 注意看题: 要求的是\([a,b]\)的子串和[c,d]的\(lcp\)的最大值 先来一下暴力吧 求出\(SA\)之后 暴力枚举\ ...

随机推荐

  1. 20个优秀的JavaScript 键盘事件处理库

    键盘事件是 Web 开发中最常用的事件之一,通过对键盘事件的捕获和处理可以提高网站的易用性和交互体验.下面,我们向大家介绍收集的20款优秀的 JavaScript 键盘事件处理库,帮助开发人员轻松处理 ...

  2. JS实现复制到剪贴板(兼容FF/Chrome/Safari所有浏览器)

    现在浏览器种类也越来越多,诸如 IE.Firefox.Chrome.Safari等等,因此现在要实现一个js复制内容到剪贴板的小功能就不是一件那么容易的事了. 在FLASH 9 时代,有一个通杀所有浏 ...

  3. Nginx之虚拟目录-root与alias的区别

    最近在nginx上部署日志分析工具awstats时,在配置awstats分析结果可供网页浏览这步时,分析结果页面访问总是404.后来查阅了一些资料,发现是root和alias的用法区别没搞懂导致的,这 ...

  4. android boot.img unpack pack

    每次编译boot.img都要花比较长的时间,有时候只是更改其中的配置文件. 如果能够将boot.img解压,更改之后再打包的话,就能节省时间. boot.img tools是别人写好的工具,能很好的解 ...

  5. 第三百二十节,Django框架,生成二维码

    第三百二十节,Django框架,生成二维码 用Python来生成二维码,需要qrcode模块,qrcode模块依赖Image 模块,所以首先安装这两个模块 生成二维码保存图片在本地 import qr ...

  6. e581. Animating an Array of Images in an Application

    This is the simplest application to animate an array of images. import java.awt.*; import javax.swin ...

  7. 在对listctrl的控件进行重载的过程中,GetHeaderCtrl()返回NULL的问题

    先谈谈我的问题吧! 在使用listctrl的过程中,我需要在列表头部添加checkbox,实现全选的功能. 经过网上资料的罗列,我找到了一个demo,使用的重绘的方法,在使用的过程中,我发现我的列表头 ...

  8. Spring配置文件加载流程

    http://blog.csdn.net/dy_paradise/article/details/6038990

  9. Linux配置防火墙,开启80port、3306port 可能会遇到的小问题

     vi /etc/sysconfig/iptables -A INPUT -m state –state NEW -m tcp -p tcp –dport 80 -j ACCEPT(同意80端口通 ...

  10. HBase原理、基本概念、基本架构-3

    HBase是Apache Hadoop的数据库,能够对大型数据提供随机.实时的读写访问.HBase的目标是存储并处理大型的数据.HBase是一个开源的,分布式的,多版本的,面向列的存储模型.它存储的是 ...