【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\)之后 暴力枚举\ ...
随机推荐
- 轻量级ORM框架Dapper应用二:使用Dapper实现CURD操作
在上一篇文章中,讲解了如何安装Dapper,这篇文章中将会讲解如何使用Dapper使用CURD操作. 例子中使用到的实体类定义如下: using System; using System.Collec ...
- TextBox控件的DataBindings属性
DataBindings属性是很多控件都有的属性,作用有2方面.一方面是用于与数据库的数据进行绑定,进行数据显示.另一方面用于与控件或类的对象进行数据绑定.这里主要关注后者.主要用法是将某个对象的某个 ...
- mysql编译安装后各种常见错误集锦
1.ERROR 2013 (HY000): Lost connection to MySQL server at 'reading initial communication packet', sys ...
- 各个层次的gcc警告
http://blog.csdn.net/lizzywu/article/details/9419145 各个层次的gcc警告从上到下覆盖 变量(代码)级:指定某个变量警告 int a __attri ...
- 第三百零一节,python操作redis缓存-管道、发布订阅
python操作redis缓存-管道.发布订阅 一.管道 redis-py默认在执行每次请求都会创建(连接池申请连接)和断开(归还连接池)一次连接操作,如果想要在一次请求中指定多个命令,则可以使用pi ...
- 初识EseNt
转自:http://www.cnblogs.com/goosao/archive/2011/09/23/2186412.html 一.什么是EseNtEseNt(Extensible Storage ...
- e675. 翻转缓冲图像
// To create a buffered image, see e666 创建缓冲图像 // Flip the image vertically AffineTransform tx = Aff ...
- V4L2编程 视频采集-范例
http://linuxtv.org/downloads/legacy/video4linux/API/V4L2_API/v4l2spec/: http://blog.csdn.net/kangear ...
- c/c++函数指针(3)
原文地址:http://blog.csdn.net/qingshuiyangfan/article/details/7692647 学习要点: 1,函数地址的一般定义和typedef简化定义; ...
- swift学习笔记之--方法
一.说明 跟oc一样,面向对象,swift重点额方法可以分为2大类: (1)实例方法 oc中为减号方法(对象方法) (2)类型方法 oc中的加号方法(类方法) 二.实例方法 只能是对象调用的方法 代码 ...