原文链接https://www.cnblogs.com/zhouzhendong/p/BZOJ4556.html

题目传送门 - BZOJ4556

题意

  给定一个长度为 $n$ 的字符串 $s$ 。

  有 $m$ 次询问,每次询问的格式为 $a,b,c,d$ ,问 $s[c\cdots d]$ 与 $\underline {s[a\cdots b]}$ 的所有子串 的 LCP 的最大值是多少。

  $n,m\leq 10^5$

题解

  首先,我们对于每一个询问考虑二分答案。显然答案的上下界分别是 $0$ 和 $d-c+1$ 。

  那么如何判断一个答案是否合法?

  假设答案为 $x$ ,那么我们要判断是否有满足条件的点。

  条件是:在 $[a,b-x+1]$ 为左端点的 $s$ 的后缀中,是否存在一个后缀,满足它与以 $\underline{c}$ 为左端点的后缀的 LCP 不小于 $x$ 。

  于是我们考虑对后缀排序,即我们跑一跑 SA 。

  那么,满足条件最后一部分的后缀的 $rank$ 必然是连续的一段。我们可以通过倍增和预处理 ST 表来找到这个左右界 $[L,R]$。

  于是,我们就将这个判断答案是否合法的问题转化成了一个不带修改的二维数点问题。其中,一个维度是 $[a,b-x+1]$ 另一个是 $[L,R]$。

  那么我们只需要写个主席树预处理一下就可以了。

  时间复杂度 $O(n\log ^2 n)$ ,我第一发交是卡着时限过去的,后来把常数写的优美了一点,跑的不是很快,$16^+s$ 。

代码

#include <bits/stdc++.h>
#define y1 _83f9
using namespace std;
const int N=100005;
int read(){
int x=0;
char ch=getchar();
while (!isdigit(ch))
ch=getchar();
while (isdigit(ch))
x=(x<<1)+(x<<3)+ch-48,ch=getchar();
return x;
}
int n,m;
int rank[N],tax[N],SA[N],tmp[N],height[N];
int ST[N][17],Log[N];
char s[N];
void Sort(int n,int m){
for (int i=1;i<=m;i++)
tax[i]=0;
for (int i=1;i<=n;i++)
tax[rank[i]]++;
for (int i=1;i<=m;i++)
tax[i]+=tax[i-1];
for (int i=n;i>=1;i--)
SA[tax[rank[tmp[i]]]--]=tmp[i];
}
bool cmp(int rk[],int x,int y,int w){
return rk[x]==rk[y]&&rk[x+w]==rk[y+w];
}
void Suffix_Array(char s[],int n){
memset(SA,0,sizeof SA);
memset(tax,0,sizeof tax);
memset(tmp,0,sizeof tmp);
memset(rank,0,sizeof rank);
memset(height,0,sizeof height);
int m=200;
for (int i=1;i<=n;i++)
rank[i]=s[i],tmp[i]=i;
Sort(n,m);
for (int w=1,p=0;p<n;w<<=1,m=p){
p=0;
for (int i=n-w+1;i<=n;i++)
tmp[++p]=i;
for (int i=1;i<=n;i++)
if (SA[i]>w)
tmp[++p]=SA[i]-w;
Sort(n,m);
swap(tmp,rank);
rank[SA[1]]=p=1;
for (int i=2;i<=n;i++)
rank[SA[i]]=cmp(tmp,SA[i],SA[i-1],w)?p:++p;
}
for (int i=1,j,k=0;i<=n;height[rank[i++]]=k)
for (k=max(k-1,0),j=SA[rank[i]-1];s[i+k]==s[j+k];k++);
}
void Get_ST(int n){
Log[1]=0;
for (int i=2;i<=n;i++){
Log[i]=Log[i>>1]+1;
ST[i][0]=height[i];
for (int j=1;j<17;j++){
ST[i][j]=ST[i][j-1];
if (i-(1<<(j-1))>0&&ST[i-(1<<(j-1))][j-1]<ST[i][j])
ST[i][j]=ST[i-(1<<(j-1))][j-1];
}
}
}
int Query(int L,int R){
int d=Log[R-L+1];
return min(ST[L+(1<<d)-1][d],ST[R][d]);
}
int LCP(int x,int y){
x=rank[x],y=rank[y];
return Query(min(x,y)+1,max(x,y));
}
// Start to build President Tree
const int S=N*20*2;
int root[N],ls[S],rs[S],sum[S],tot=0;
int newnode(){
tot++;
ls[tot]=rs[tot]=sum[tot]=0;
return tot;
}
void build(int &rt,int L,int R){
rt=newnode();
if (L==R)
return;
int mid=(L+R)>>1;
build(ls[rt],L,mid);
build(rs[rt],mid+1,R);
}
void update(int prt,int &rt,int L,int R,int x,int v){
if (!rt||rt==prt)
rt=newnode(),sum[rt]=sum[prt];
sum[rt]+=v;
if (L==R)
return;
if (!ls[rt])
ls[rt]=ls[prt];
if (!rs[rt])
rs[rt]=rs[prt];
int mid=(L+R)>>1;
if (x<=mid)
update(ls[prt],ls[rt],L,mid,x,v);
else
update(rs[prt],rs[rt],mid+1,R,x,v);
}
int query(int prt,int rt,int L,int R,int xL,int xR){
if (L>xR||R<xL)
return 0;
if (xL<=L&&R<=xR)
return sum[rt]-sum[prt];
int mid=(L+R)>>1;
return query(ls[prt],ls[rt],L,mid,xL,xR)
+query(rs[prt],rs[rt],mid+1,R,xL,xR);
}
int Query(int x1,int x2,int y1,int y2){
return query(root[x1-1],root[x2],1,n,y1,y2);
}
bool check(int k,int x,int a,int b){
if (k==0)
return 1;
if (b-a+1<k)
return 0;
int L=x,R=x;
for (int i=16;i>=0;i--){
if (L-(1<<i)>=1&&Query(L-(1<<i)+1,x)>=k)
L-=1<<i;
if (R+(1<<i)<=n&&Query(x+1,R+(1<<i))>=k)
R+=1<<i;
}
return Query(a,b-k+1,L,R);
}
int main(){
n=read(),m=read();
scanf("%s",s+1);
Suffix_Array(s,n);
Get_ST(n);
build(root[0],1,n);
for (int i=1;i<=n;i++)
update(root[i-1],root[i],1,n,rank[i],1);
while (m--){
int L1=read(),R1=read(),L2=read(),R2=read();
int L=0,R=R2-L2+1,mid,ans=0;
while (L<=R){
int mid=(L+R)>>1;
if (check(mid,rank[L2],L1,R1))
L=mid+1,ans=mid;
else
R=mid-1;
}
printf("%d\n",ans);
}
return 0;
}

  

BZOJ4556 [Tjoi2016&Heoi2016]字符串 SA ST表 二分答案 主席树的更多相关文章

  1. BZOJ 4556: [Tjoi2016&Heoi2016]字符串(后缀数组 + 二分答案 + 主席树 + ST表 or 后缀数组 + 暴力)

    题意 一个长为 \(n\) 的字符串 \(s\),和 \(m\) 个询问.每次询问有 \(4\) 个参数分别为 \(a,b,c,d\). 要你告诉它 \(s[a...b]\) 中的所有子串 和 \(s ...

  2. BZOJ2534 Uva10829L-gap字符串 字符串 SA ST表

    原文链接https://www.cnblogs.com/zhouzhendong/p/9240665.html 题目传送门 - BZOJ2534 题意 有一种形如 $uvu$ 形式的字符串,其中 $u ...

  3. BZOJ5343: [Ctsc2018]混合果汁 二分答案+主席树

    分析: 整体二分或二分答案+主席树,反正没有要求强制在线,两个都可以做... 贪心还是比较显然的,那么就是找前K大的和...和CQOI的任务查询系统很像 附上代码: #include <cstd ...

  4. BZOJ_5343_[Ctsc2018]混合果汁_二分答案+主席树

    BZOJ_5343_[Ctsc2018]混合果汁_二分答案+主席树 题意:给出每个果汁的价格p,美味度d,最多能放的体积l.定义果汁混合后的美味度为果汁的美味度的最小值. m次询问,要求花费不大于g, ...

  5. 2019杭电多校第四场hdu6621 K-th Closest Distance(二分答案+主席树)

    K-th Closest Distance 题目传送门 解题思路 二分答案+主席树 先建主席树,然后二分答案mid,在l和r的区间内查询[p-mid, p+mid]的范围内的数的个数,如果大于k则说明 ...

  6. [BZOJ4556][TJOI2016&&HEOI2016]字符串(二分答案+后缀数组+RMQ+主席树)

    4556: [Tjoi2016&Heoi2016]字符串 Time Limit: 20 Sec  Memory Limit: 128 MBSubmit: 1360  Solved: 545[S ...

  7. [BZOJ4556][Tjoi2016&Heoi2016]字符串 主席树+二分+倍增+后缀自动机

    4556: [Tjoi2016&Heoi2016]字符串 Time Limit: 20 Sec  Memory Limit: 128 MBSubmit: 1215  Solved: 484[S ...

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

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

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

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

随机推荐

  1. MySql 使用规范推荐(转)

    在java应用开发中深知数据库的重要性,绝大多数情况下数据库的性能决定了程序的性能,前期如果埋下的坑越多到后期会成为整个程序的瓶颈,所以希望java开发者一定要重视!!!! 一.基础规范 1.使用In ...

  2. reportNG定制化之失败截图及日志

    先从github上拉下 reportNg的源代码 reportng  拉下源码后我们使用IDEA进行导入 1.reportng.properties 增加部分类表项 这里我们直接在末尾添加 log=L ...

  3. windows修复分区卷:chkdsk

    问题描述: 共享磁盘上传文件到服务器报错:一个意外错误使你无法复制该文件夹.如果你继续收到此错误,可以使用错误代码来搜索有关问题的帮助,错误 0x800703E3:由于线程退出或应用程序请求,已终止I ...

  4. C#生成Excel保存到服务器端并下载

    using MongoDB.Bson; using Newtonsoft.Json.Linq; using NPOI.HSSF.UserModel; using NPOI.SS.UserModel; ...

  5. maven install 报错 No compiler is provided in this environment. Perhaps you are running on a JRE rather than a JDK?

    1.控制台打印信息 [INFO] Scanning for projects... [INFO] [INFO] ---------------------< org.cqupt.mauger:R ...

  6. BeautifulSoup的基本操作

    >>> from bs4 import BeautifulSoup   #导入 >>> soup = BeautifulSoup(url.content," ...

  7. UEFI rootkit 工具LoJax可以感染电脑主板(mainboard)

    1.UEFI(Unified Extensible Firmware Interface)统一扩展接口,UEFI rootkit是以在UEFI中植入rootkit ,18年9月份ESET首次公开了境外 ...

  8. poj3662 二分+最短路

    /* 给定一张无向图,要求找到1-n的路径,该路径上第k+1大的边是所有路径上最小的 如果没有1-n的路,那么输出-1 二分答案mid,遍历一次所有边,如果边权小于mid,则设为0,大于mid,则设为 ...

  9. 20165314 2016-2017-2 《Java程序设计》第3周学习总结

    20165314 2016-2017-2 <Java程序设计>第3周学习总结 教材学习内容总结 类体包含成员变量和域变量 局部变量只在方法内有效 对象的创建以及对象对自己变量和方法通过用. ...

  10. Python序列[1,2,3,4,5]

    序列是用于存放多个值得连续空间,并按一定顺序排列,每一个值(称为元素)都分配一个数,称为索引或位置.通过该索引可以取出相应的值. 索引 序列中的元素都是有序的.拥有自己编号(从0开始),我们可以通过索 ...