【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\)之后 暴力枚举\ ...
随机推荐
- 12款优秀 jQuery Ajax 分页插件和教程
12款优秀 jQuery Ajax 分页插件和教程 在这篇文章中,我为大家收集了12个基于 jQuery 框架的 Ajax 分页插件,这些插件都提供了详细的使用教程和演示.Ajax 技术的出现使得 W ...
- 安装 Windows SDK for Windows 7 时遇到的一个问题及解决办法
最近试着用 VS2010 + Qt 开发程序,发现 VS2010 里面没有提供单独的调试器 cdb,这样用 Qt Creator 时就无法设置断点调试,很不方便.想起 Windows SDK for ...
- 数据库 Mysql内容补充二
多表查询 mysql支持的是SQL99标准的连接查询,并不支持oracle公司的外连接查询, 但是支持oracle等值查询,不等值查询,自连接查询,子查询(只要不是外连接(+)都支持) oracle也 ...
- QT全局宏变量的实现
qt中如何实现定义一个宏,在整个工程中都可以实现呢?下面我来写一个亲测的例子: pro中添加如下宏定义代码: DEFINES += HELLO=\"$$PWD/\" DEFINES ...
- Extracting and composing robust features with denosing autoencoders 论文
这是一篇发表于2008年初的论文. 文章主要讲了利用 denosing autoencoder来学习 robust的中间特征..进上步,说明,利用这个方法,可以初始化神经网络的权值..这就相当于一种非 ...
- DTD -- XML验证
DTD(文档类型定义)的作用是定义 XML 文档的合法构建模块. DTD 可被成行地声明于 XML 文档中,也可作为一个外部引用. DTD简介 内部的 DOCTYPE 声明 假如 DTD 被包含在您的 ...
- 转载:Create a Flash Login System Using PHP and MySQL
本文共两部分: 1. http://dev.tutsplus.com/tutorials/create-a-flash-login-system-using-php-and-mysql-part-1- ...
- centos6下时间同步(ntp)操作
1.时间同步的重要性 时间同步可以保证业务的正常运行,比如数据同步,比如系统计划任务的批量执行.等. 2.查看自己的系统时间. [root@localhost ~]# date 3.系统修改时间 # ...
- 用json在java和C#之间传递base64的问题。。。
记录下..唉.... java代码: 导入这个 commons-codec-1.8.jar (下载链接: http://files.cnblogs.com/files/gaocong/jar%E5%8 ...
- 获取pc硬件信息杂记
//Download by http://www.NewXing.com #include "StdAfx.h" #include "RegUtil.h" #i ...