【BZOJ4556】[Tjoi2016&Heoi2016]字符串 后缀数组+二分+主席树+RMQ
【BZOJ4556】[Tjoi2016&Heoi2016]字符串
Description
Input
Output
对于每一次询问,输出答案。
Sample Input
aaaaa
1 1 1 5
1 5 1 1
2 3 2 3
2 4 2 3
2 3 2 4
Sample Output
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的更多相关文章
- bzoj4556: [Tjoi2016&Heoi2016]字符串 (后缀数组加主席树)
题目是给出一个字符串,每次询问一个区间[a,b]中所有的子串和另一个区间[c,d]的lcp最大值,首先求出后缀数组,对于lcp的最大值肯定是rank[c]的前驱和后继,但是对于这个题会出现问题,就是题 ...
- [BZOJ4556][Tjoi2016&Heoi2016]字符串 后缀数组+主席树
4556: [Tjoi2016&Heoi2016]字符串 Time Limit: 20 Sec Memory Limit: 128 MB Description 佳媛姐姐过生日的时候,她的小 ...
- 【BZOJ-4556】字符串 后缀数组+二分+主席树 / 后缀自动机+线段树合并+二分
4556: [Tjoi2016&Heoi2016]字符串 Time Limit: 20 Sec Memory Limit: 128 MBSubmit: 657 Solved: 274[Su ...
- Bzoj4556: [Tjoi2016&Heoi2016]字符串 后缀数组
4556: [Tjoi2016&Heoi2016]字符串 Time Limit: 20 Sec Memory Limit: 128 MBSubmit: 169 Solved: 87[Sub ...
- BZOJ 4556 [Tjoi2016&Heoi2016]字符串 ——后缀数组 ST表 主席树 二分答案
Solution 1: 后缀数组暴力大法好 #include <map> #include <cmath> #include <queue> #include &l ...
- [HEOI2016/TJOI2016]字符串(后缀数组+二分+主席树/后缀自动机+倍增+线段树合并)
后缀数组解法: 先二分最长前缀长度 \(len\),然后从 \(rnk[c]\) 向左右二分 \(l\) 和 \(r\) 使 \([l,r]\) 的 \(height\geq len\),然后在主席树 ...
- BZOJ4556:[TJOI\HEOI2016]字符串(后缀数组,主席树,二分,ST表)
Description 佳媛姐姐过生日的时候,她的小伙伴从某东上买了一个生日礼物.生日礼物放在一个神奇的箱子中.箱子外边写了一个长为n的字符串s,和m个问题.佳媛姐姐必须正确回答这m个问题,才能打开箱 ...
- bzoj 4556 [Tjoi2016&Heoi2016]字符串——后缀数组+主席树
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=4556 本来只要查 ht[ ] 数组上的前驱和后继就行,但有长度的限制.可以二分答案解决!然后 ...
- 【BZOJ4556】字符串(后缀数组,主席树)
[BZOJ4556]字符串(后缀数组,主席树) 题面 BZOJ 题解 注意看题: 要求的是\([a,b]\)的子串和[c,d]的\(lcp\)的最大值 先来一下暴力吧 求出\(SA\)之后 暴力枚举\ ...
随机推荐
- node-webkit连接mysql
一.安装node.js mysql驱动库 node-webkit里面没有mysql模块的,我们需要安装mysql模块.我们可以使用npm(Node package manager)进行安装.这里使用到 ...
- IoC就是IoC,不是什么技术,与GoF一样,是一种 设计模式。
IoC就是IoC,不是什么技术,与GoF一样,是一种 设计模式. Interface Driven Design接口驱动,接口驱动有很多好处,可以提供不同灵活的子类实现,增加代码稳定和健壮性等等,但是 ...
- Storm On YARN带来的优点
1)弹性计算资源 将storm执行在yarn上后,Storm能够与其它计算框架(如mapreduce)共享整个集群的资源.这样当Storm负载骤增时,可动态为它添加计算资源. 负载减小时,能够 ...
- Oracle 添加主键和索引
数据的主键和索引一般情况下都是必须的,特别是表有大量数据的时候,索引和主键更是必不可少,这样可以提供数据的查询效率: 一.创建表的同时创建主键约束 (1)无命名 create table studen ...
- CPU性能判断指标---上下文切换,运行队列和使用率
http://blog.chinaunix.net/uid-15007890-id-3064254.html uptime11:35:08 up 21:57, 6 users, load aver ...
- 使用Visual Studio将C#生成DLL文件的方法
1.命令方式 打开Visual Studio安装目录下的开发人员命令提示 译 File.cs 以产生 File.exe csc File.cs 编译 File.cs 以产生 File.dll csc ...
- MathType编辑双向斜箭头的教程
箭头是一个很常见的符号,不只是在数学中,在各个方面出现的频率都很高,因此在数学公式中出现时,用MathType公式编辑器编辑公式时也要尽量地能够编辑出这些符号.箭头符号在MathType中有很多,使用 ...
- datatables隐藏列排序
var tableOption = { id: 'cacScriptTable', order: [[2, 'desc'],[1, 'desc']],//以第三列‘updatedAt’排序,如果第三列 ...
- Windows "计划任务"功能设置闹钟~
相信很多人和我一样在使用电脑时都会遇到这样一个麻烦:不知道如何在windows 中设置一个闹铃.当我们在“开始”菜单的所有程序中找了一遍又一遍,甚至使用Everything.exe做全盘的搜索,都没有 ...
- supervisorctl unix:///var/run/supervisor.sock refused connection
运行supervisorct 报如下错误 supervisorctl unix:///var/run/supervisor.sock refused connection 查看supervisord. ...