BZOJ4556:[TJOI\HEOI2016]字符串(后缀数组,主席树,二分,ST表)
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
Solution
设$suf_i$表示后缀$i$,
首先考虑二分一个答案$mid$,那么现在问题转化成求$suf_a$到$suf_{b-mid+1}$的这些个后缀中,是否有一个后缀和$suf(c)$的$lcp$大于等于$mid$。
设$SA_i$表示后缀排序排名为$i$的后缀,$Rank_i$表示$suf_i$的后缀排序排名。
由于对于$suf_c$,我们可以用二分+$ST$表求出后缀排序中的可行区间,可行区间内的后缀和$suc_c$的$lcp$长度都大于等于$mid$。现在问题转化为了求$suf_a$到$suf_{b-mid+1}$的这些后缀是否哪个后缀的$Rank$值在可行区间内,这个用一个主席树就好了。
Code
#include<iostream>
#include<cstring>
#include<cstdio>
#define N (100009)
using namespace std; struct Sgt{int ls,rs,val;}Segt[N*];
int Root[N],sgt_num;
int n,q,m=,a,b,c,d;
int ST[N][],LOG2[N];
int wa[N],wb[N],wt[N],SA[N],Height[N],Rank[N];
char r[N]; inline int read()
{
int x=,w=; char c=getchar();
while (c<'' || c>'') {if (c=='-') w=-; c=getchar();}
while (c>='' && c<='') x=x*+c-'', c=getchar();
return x*w;
} bool cmp(int *y,int a,int b,int k)
{
int arank1=y[a];
int brank1=y[b];
int arank2=a+k>=n?-:y[a+k];
int brank2=b+k>=n?-:y[b+k];
return arank1==brank1 && arank2==brank2;
} void Build_SA()
{
int *x=wa,*y=wb;
for (int i=; i<m; ++i) wt[i]=;
for (int i=; i<n; ++i) ++wt[x[i]=r[i]-'a'];
for (int i=; i<m; ++i) wt[i]+=wt[i-];
for (int i=n-; i>=; --i) SA[--wt[x[i]]]=i; for (int j=; j<=n; j<<=)
{
int p=;
for (int i=n-j; i<n; ++i) y[p++]=i;
for (int i=; i<n; ++i) if (SA[i]>=j) y[p++]=SA[i]-j; for (int i=; i<m; ++i) wt[i]=;
for (int i=; i<n; ++i) ++wt[x[y[i]]];
for (int i=; i<m; ++i) wt[i]+=wt[i-];
for (int i=n-; i>=; --i) SA[--wt[x[y[i]]]]=y[i]; m=; swap(x,y);
x[SA[]]=;
for (int i=; i<n; ++i)
x[SA[i]]=cmp(y,SA[i],SA[i-],j)?m-:m++;
if (m>=n) break;
}
} void Build_Height()
{
for (int i=; i<n; ++i) Rank[SA[i]]=i;
int k=;
for (int i=; i<n; ++i)
{
if (!Rank[i]) continue;
if (k) k--;
int j=SA[Rank[i]-];
while (r[i+k]==r[j+k]) ++k;
Height[Rank[i]]=k;
}
} void Build_ST()
{
for (int i=; i<=n; ++i) LOG2[i]=LOG2[i>>]+;
for (int i=; i<n; ++i) ST[i][]=Height[i];
for (int j=; j<=; ++j)
for (int i=; i+(<<j)-<n; ++i)
ST[i][j]=min(ST[i][j-],ST[i+(<<j-)][j-]);
} int Query(int l,int r)
{
int k=LOG2[r-l+];
return min(ST[l][k],ST[r-(<<k)+][k]);
} int Update(int pre,int l,int r,int x)
{
int now=++sgt_num;
Segt[now]=Segt[pre];
Segt[now].val++;
if (l==r) return now;
int mid=(l+r)>>;
if (x<=mid) Segt[now].ls=Update(Segt[now].ls,l,mid,x);
else Segt[now].rs=Update(Segt[now].rs,mid+,r,x);
return now;
} int Query(int u,int v,int l,int r,int l1,int r1)
{
if (l>r1 || r<l1) return ;
if (l1<=l && r<=r1) return Segt[v].val-Segt[u].val;
int mid=(l+r)>>;
return Query(Segt[u].ls,Segt[v].ls,l,mid,l1,r1)+Query(Segt[u].rs,Segt[v].rs,mid+,r,l1,r1);
} bool check(int lim)
{
int l,r,L,R;
l=,r=Rank[c]-,L=Rank[c];
while (l<=r)
{
int mid=(l+r)>>;
if (Query(mid+,Rank[c])>=lim) L=mid,r=mid-;
else l=mid+;
}
l=Rank[c]+,r=n-,R=Rank[c];
while (l<=r)
{
int mid=(l+r)>>;
if (Query(Rank[c]+,mid)>=lim) R=mid,l=mid+;
else r=mid-;
}
if (Query(Root[a],Root[b-lim+],,n,L,R)) return true;
return false;
} int main()
{
n=read(); q=read();
scanf("%s",r);
Build_SA(); Build_Height();
Build_ST();
for (int i=; i<=n; ++i)
Root[i]=Update(Root[i-],,n,Rank[i-]);
while (q--)
{
a=read()-; b=read()-; c=read()-; d=read()-;
int l=,r=min(b-a+,d-c+),ans=;
while (l<=r)
{
int mid=(l+r)>>;
if (check(mid)) ans=mid, l=mid+;
else r=mid-;
}
printf("%d\n",ans);
}
}
BZOJ4556:[TJOI\HEOI2016]字符串(后缀数组,主席树,二分,ST表)的更多相关文章
- BZOJ3473:字符串(后缀数组,主席树,二分,ST表)
Description 给定n个字符串,询问每个字符串有多少子串(不包括空串)是所有n个字符串中至少k个字符串的子串? Input 第一行两个整数n,k. 接下来n行每行一个字符串. Output 一 ...
- [BZOJ4556][Tjoi2016&Heoi2016]字符串 后缀数组+主席树
4556: [Tjoi2016&Heoi2016]字符串 Time Limit: 20 Sec Memory Limit: 128 MB Description 佳媛姐姐过生日的时候,她的小 ...
- BZOJ4556 [Tjoi2016&Heoi2016]字符串 【后缀数组 + 主席树 + 二分 + ST表】
题目 佳媛姐姐过生日的时候,她的小伙伴从某东上买了一个生日礼物.生日礼物放在一个神奇的箱子中.箱子外边写了 一个长为n的字符串s,和m个问题.佳媛姐姐必须正确回答这m个问题,才能打开箱子拿到礼物,升职 ...
- [HEOI2016] 字符串 - 后缀数组,主席树,ST表,二分
[HEOI2016] 字符串 Description 给定一个字符串 \(S\), 有 \(m\) 个询问,每个询问给定参数 \((a,b,c,d)\) ,求 \(s[a..b]\) 的子串与 \(s ...
- bzoj 4556 [Tjoi2016&Heoi2016]字符串——后缀数组+主席树
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=4556 本来只要查 ht[ ] 数组上的前驱和后继就行,但有长度的限制.可以二分答案解决!然后 ...
- P4094 [HEOI2016/TJOI2016]字符串 后缀数组+主席树+二分答案
$ \color{#0066ff}{ 题目描述 }$ 佳媛姐姐过生日的时候,她的小伙伴从某东上买了一个生日礼物.生日礼物放在一个神奇的箱子中.箱子外边写了一个长为n的字符串s,和m个问题.佳媛姐姐必须 ...
- bzoj4556: [Tjoi2016&Heoi2016]字符串 (后缀数组加主席树)
题目是给出一个字符串,每次询问一个区间[a,b]中所有的子串和另一个区间[c,d]的lcp最大值,首先求出后缀数组,对于lcp的最大值肯定是rank[c]的前驱和后继,但是对于这个题会出现问题,就是题 ...
- Bzoj4556: [Tjoi2016&Heoi2016]字符串 后缀数组
4556: [Tjoi2016&Heoi2016]字符串 Time Limit: 20 Sec Memory Limit: 128 MBSubmit: 169 Solved: 87[Sub ...
- bzoj 4556 字符串 —— 后缀数组+主席树
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=4556 就是找一个 rk 在一段区间内的前驱和后继: 由于 LCP 还有区间长度的限制,所以可 ...
随机推荐
- c++ 重载、覆盖 (隐藏)(virtual)
背景:不用说,学习C++的你,一定知道这是个词--至于难不难懂,就看你的理解能力了,我理解也是费劲千辛万苦啊,成员函数的重载.覆盖(override).隐藏.virtual 很容易混淆,C++程序员必 ...
- MyBatis动态添加—trim标签
做添加时,部分字段有值,没值的字段不添加,这就是动态添加,使用 trim 标签就可以实现. <insert id="insertSysUser" parameterType= ...
- 青蛙的约会(poj1061+欧几里德)
青蛙的约会 Time Limit: 1000MS Memory Limit: 10000K Total Submissions: 94174 Accepted: 17412 Descripti ...
- POJ3693(SummerTrainingDay10-J 后缀数组)
Maximum repetition substring Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 10241 Ac ...
- 【 js 基础 】【 源码学习 】源码设计 (更新了backbone分析)
学习源码,除了学习对一些方法的更加聪明的代码实现,同时也要学习源码的设计,把握整体的架构.(推荐对源码有一定熟悉了之后,再看这篇文章) 目录结构:第一部分:zepto 设计分析 第二部分:unders ...
- LOJ2522:[FJOI2018]邮递员问题(乱搞)
传送门 乱搞. 可以发现如果起点在左边界,终点在右边界的时候上下走的点一定是连续的(可能吧) 那么可以设 \(f_{i,j,0/1}\) 表示当前上面到 \(i\),下面到 \(j\),当前在上面/下 ...
- 【代码笔记】iOS-Label随字自动变大
一,效果图. 二,工程图. 三, 代码. RootViewController.h #import <UIKit/UIKit.h> //添加HPGrowingTextView头文件 #im ...
- tinyint、smallint、bigint、int 区别
1byte=8bit [tinyint] 从 0 到 255 的整型数据.存储大小为 1 字节.如果设置为UNSIGNED类型,只能存储从0到255的整数,不能用来储存负数. [smallint] ...
- offsetTop 实现滚动条内内容定位
js代码: var _parent_top = document.getElementsByClassName('parent')[0].offsetTop;var _phase_top = docu ...
- Component Interface相关面试题
下面的列表中的问题很常见,Component Interface是很重要的.你知道基本知识比知道答案更重要. Q:以下陈述是错误的. A:一个Component Interface 可以map多个Pe ...