Solution 1:

后缀数组暴力大法好

#include <map>
#include <cmath>
#include <queue>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
#define F(i,j,k) for (int i=j;i<=k;++i)
#define D(i,j,k) for (int i=j;i>=k;--i)
#define ll long long
#define mp make_pair
#define maxn 300005 struct Suffix_Array{
int s[maxn];
int tmp[maxn],rk[maxn],sa[maxn],cnt[maxn],h[maxn];
void build(int n,int m)
{
int i,j,k; n++;
F(i,0,2*n+5) tmp[i]=rk[i]=sa[i]=h[i]=0;
F(i,0,m-1) cnt[i]=0;
F(i,0,n-1) cnt[rk[i]=s[i]]++;
F(i,1,m-1) cnt[i]+=cnt[i-1];
F(i,0,n-1) sa[--cnt[rk[i]]]=i;
for (int k=1;k<=n;k<<=1)
{
F(i,0,n-1){j=sa[i]-k;if(j<0)j+=n;tmp[cnt[rk[j]]++]=j;}
sa[tmp[cnt[0]=0]]=j=0;
F(i,1,n-1)
{
if (rk[tmp[i]]!=rk[tmp[i-1]]||rk[tmp[i]+k]!=rk[tmp[i-1]+k]) cnt[++j]=i;
sa[tmp[i]]=j;
}
memcpy(rk,sa,(n+1)*sizeof (int)); memcpy(sa,tmp,(n+1)*sizeof (int));
if (j>=n-1) break;
}
for (i=k=0;i<n;h[rk[i++]]=k)
for (k?k--:0,j=sa[rk[i]-1];s[i+k]==s[j+k];k++);
}
void work(int n,int m)
{
F(t,1,m)
{
int a,b,c,d;scanf("%d%d%d%d",&a,&b,&c,&d); a--;b--;c--;d--;
int mx=0,mn=d-c+1,mid=rk[c];
if (a<=c&&b>=c) mx=min(d-c+1,b-c+1);
for (int i=mid;i>1;--i)
{
if (mn<=mx) break;
mn=min(mn,h[i]);
if (sa[i-1]>=a&&sa[i-1]<=b)
mx=max(mx,min(mn,b-sa[i-1]+1));
}
mn=d-c+1;
for (int i=mid+1;i<=n;++i)
{
if (mn<=mx) break;
mn=min(mn,h[i]);
if (sa[i]>=a&&sa[i]<=b)
mx=max(mx,min(mn,b-sa[i]+1));
}
printf("%d\n",mx);
}
}
}SA; int n,m;
char s[maxn]; int main()
{
scanf("%d%d",&n,&m);
scanf("%s",s);
F(i,0,n-1) SA.s[i]=s[i]-'a'+1; SA.s[n]=0;
SA.build(n,30); SA.work(n,m);
}

  

Solution 2:

后缀数组 二分答案 主席数 ST表

每次询问二分答案,然后找出要匹配的串在SA中最左以及最右的位置,然后主席树判断即可。这样貌似是两个$\log$

可以在主席树上直接找前驱后继,然后ST表直接查询,然后就成了一个$\log$

我比较菜,写的是第一种。不过一次写对还是挺欣慰的,(废话,你慢慢写了3h)

#include <map>
#include <cmath>
#include <queue>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
#define F(i,j,k) for (int i=j;i<=k;++i)
#define D(i,j,k) for (int i=j;i>=k;--i)
#define mp make_pair
#define maxn 200005 namespace SA{
int tmp[maxn],s[maxn],cnt[maxn],rk[maxn],sa[maxn],h[maxn];
int st[maxn][21],_log[maxn];
void build(int n,int m)
{
int i,j,k; n++;
F(i,0,2*n+1) tmp[i]=rk[i]=sa[i]=h[i]=0;
F(i,0,m-1) cnt[i]=0;
F(i,0,n-1) cnt[rk[i]=s[i]]++;
F(i,1,m-1) cnt[i]+=cnt[i-1];
F(i,0,n-1) sa[--cnt[rk[i]]]=i;
for (int k=1;k<=n;k<<=1)
{
F(i,0,n-1){j=sa[i]-k;if(j<0)j+=n;tmp[cnt[rk[j]]++]=j;}
sa[tmp[cnt[0]=0]]=j=0;
F(i,1,n-1)
{
if (rk[tmp[i]]!=rk[tmp[i-1]]||rk[tmp[i]+k]!=rk[tmp[i-1]+k]) cnt[++j]=i;
sa[tmp[i]]=j;
}
memcpy(rk,sa,(n+1)*sizeof(int)); memcpy(sa,tmp,(n+1)*sizeof(int));
if (j>=n-1) break;
}
for (i=k=0;i<n;h[rk[i++]]=k) for (k?k--:0,j=sa[rk[i]-1];s[i+k]==s[j+k];k++);
F(i,1,n-1) st[i][0]=h[i];
F(i,2,n-1) _log[i]=_log[i>>1]+1;
F(i,1,20) F(j,1,n-(1<<i)) st[j][i]=min(st[j][i-1],st[j+(1<<i-1)][i-1]);
}
int query(int a,int b,int n)
{
if (a==b) return n-sa[a]; a++;
int tmp=_log[b-a+1];
return min(st[a][tmp],st[b-(1<<tmp)+1][tmp]);
}
int lcp(int a,int b,int n)
{
a=rk[a],b=rk[b];
if (a>b) swap(a,b); if (a==b) return n-sa[a];
a++; int tmp=_log[b-a+1];
return min(st[a][tmp],st[b-(1<<tmp)+1][tmp]);
}
} namespace PT{
int ls[maxn<<4],rs[maxn<<4],sum[maxn<<4],rt[maxn],tot=0;
void modify(int o1,int & o2,int l,int r,int X,int f)
{
o2=++tot;sum[o2]=sum[o1]+f;if (l==r) return ;int mid=l+r>>1;
if (X<=mid) rs[o2]=rs[o1],modify(ls[o1],ls[o2],l,mid,X,f);
else ls[o2]=ls[o1],modify(rs[o1],rs[o2],mid+1,r,X,f);
}
int query(int o1,int o2,int l,int r,int L,int R)
{
if (L<=l&&r<=R) return sum[o2]-sum[o1];
int mid=l+r>>1,ret=0;
if (L<=mid) ret+=query(ls[o1],ls[o2],l,mid,L,R);
if (R>mid) ret+=query(rs[o1],rs[o2],mid+1,r,L,R);
return ret;
}
} int n,m;char s[maxn]; bool check(int l,int r,int x,int mid)
{
int pos=SA::rk[x]; //printf("The Postion is %d\n",pos);
int ll=1,rr=pos,posl,posr;
while (ll<rr)
{
int mmiidd=(ll+rr)/2;
if (SA::query(mmiidd,pos,n)>=mid) rr=mmiidd;
else ll=mmiidd+1;
}
posl=rr;
ll=pos,rr=n;
while (ll<rr)
{
int mmiidd=(ll+rr)/2+1;
if (SA::query(pos,mmiidd,n)>=mid) ll=mmiidd;
else rr=mmiidd-1;
}
posr=ll;
if (PT::query(PT::rt[l-1],PT::rt[r],1,n,posl,posr)) return true;
else return false;
} int main()
{
scanf("%d%d",&n,&m);
scanf("%s",s); F(i,0,n-1) SA::s[i]=s[i]-'a'+1; SA::s[n]=0;
SA::build(n,30);
F(i,0,n-1)
{
PT::modify(PT::rt[i-1],PT::rt[i],1,n,SA::rk[i],1);
}
F(i,1,m)
{
int a,b,c,d,mx;
scanf("%d%d%d%d",&a,&b,&c,&d);
a--;b--;c--;d--;
if (a<=c&&c<=b) mx=min(b-c+1,d-c+1); else mx=0;
int l=mx,r=min(d-c+1,b-a+1);
while (l<r)
{
int mid=(l+r)/2+1;
if (check(a,b-mid+1,c,mid)) l=mid;
else r=mid-1;
}
printf("%d\n",l);
}
}

  

BZOJ 4556 [Tjoi2016&Heoi2016]字符串 ——后缀数组 ST表 主席树 二分答案的更多相关文章

  1. bzoj 4556 [Tjoi2016&Heoi2016]字符串——后缀数组+主席树

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=4556 本来只要查 ht[ ] 数组上的前驱和后继就行,但有长度的限制.可以二分答案解决!然后 ...

  2. Bzoj 4556: [Tjoi2016&Heoi2016]字符串

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

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

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

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

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

  5. 【BZOJ4556】[Tjoi2016&Heoi2016]字符串 后缀数组+二分+主席树+RMQ

    [BZOJ4556][Tjoi2016&Heoi2016]字符串 Description 佳媛姐姐过生日的时候,她的小伙伴从某东上买了一个生日礼物.生日礼物放在一个神奇的箱子中.箱子外边写了一 ...

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

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

  7. ●BZOJ 4556 [Tjoi2016&Heoi2016]字符串

    题链: http://www.lydsy.com/JudgeOnline/problem.php?id=4556 题解: 巨恶心...但是题很好呀,可以练习好几个比较麻烦的算法~ 1).预处理 首先用 ...

  8. bzoj4556: [Tjoi2016&Heoi2016]字符串 (后缀数组加主席树)

    题目是给出一个字符串,每次询问一个区间[a,b]中所有的子串和另一个区间[c,d]的lcp最大值,首先求出后缀数组,对于lcp的最大值肯定是rank[c]的前驱和后继,但是对于这个题会出现问题,就是题 ...

  9. BZOJ 2119: 股市的预测 [后缀数组 ST表]

    2119: 股市的预测 Time Limit: 10 Sec  Memory Limit: 259 MBSubmit: 331  Solved: 153[Submit][Status][Discuss ...

随机推荐

  1. 日常-acm-韩信点兵

    相传韩信才智过人,从不直接清点自己军队的人数,只要让士兵先后以三人一排,五人一排,七人一排地变换队形,而他每次只看一眼队伍的排尾就知道人数了.输入包含多组数据,每组数据包含三个非负整数a,b,c,表示 ...

  2. 【模拟】HHHOJ#251. 「NOIP模拟赛 伍」高精度

    积累模拟经验 题目描述 维护一个二进制数,支持如下操作 "+" 该数加 11 "-" 该数减 11 "*" 该数乘 22 "\&q ...

  3. Laravel中chunk组块结果集处理

    如果你需要处理成千上万个 Eloquent 结果,可以使用 chunk 命令.chunk 方法会获取一个“组块”的 Eloquent 模型,并将其填充到给定闭包进行处理.使用 chunk 方法能够在处 ...

  4. 用\r做出进度条

    在做ftp作业的时候,需要做一个上传和下载的进度条,做的时候发现用\r很容易就能做出来 def show_progress(self, has, total): rate = float(has) / ...

  5. 基于IAR6或者IAR7建立STM32开发工程(通过实际测试,使用IAR6.30.4)

    IAR和keil两个开发平台都是arm开发当中比较流行的平台,keil4的版本之间,可以兼容,但是版本4和版本5还是不兼容的,但是IAR的兼容性更加差,好像6.30.x之间是能够兼容的吧,没有实测过, ...

  6. micrium ucprobe使用笔记

    前段时间在学习ucos-iii的时候,用到了micrium ucprobe,发现在调试的时候,很方便,可以直观的看到任务的运行使用情况,全局变量的值变化等,当然详细的可以参考官方文档,也可以参考网上的 ...

  7. UVa - 1593 代码对齐(STL)

    看上去十分麻烦的一道题,但是看了看别人的写法感觉大神们写的无比简单. 就是记一个每列单词的最大长度,然后剩下的事交给NB的iomanip头文件就好. stringsteam是一个神奇的东西. #inc ...

  8. ReportViewer部分使用总结

    最近winform上使用ReportViewer做报表,因为之前没弄过,所以遇到了很多问题,现在总结一下. 一.运行环境 .net环境:4.0 开发工具:vs2010 二.开发步骤 第一步,在winf ...

  9. javaweb通过接口来实现多个文件压缩和下载(包括单文件下载,多文件批量下载)

    原博客地址:https://blog.csdn.net/weixin_37766296/article/details/80044000 将多个文件压缩并下载下来:(绿色为修改原博客的位置) 注意:需 ...

  10. Python虚拟机之异常控制流(五)

    Python中的异常控制语义结构 在Python虚拟机之异常控制流(四)这一章中,我们考察了Python的异常在虚拟机中的级别上是什么东西,抛出异常这个动作在虚拟机的级别上对应的行为,最后,我们还剖析 ...