4556: [Tjoi2016&Heoi2016]字符串

Time Limit: 20 Sec  Memory Limit: 128 MB

Description

佳媛姐姐过生日的时候,她的小伙伴从某东上买了一个生日礼物。生日礼物放在一个神奇的箱子中。箱子外边写了
一个长为n的字符串s,和m个问题。佳媛姐姐必须正确回答这m个问题,才能打开箱子拿到礼物,升职加薪,出任CE
O,嫁给高富帅,走上人生巅峰。每个问题均有a,b,c,d四个参数,问你子串s[a..b]的所有子串和s[c..d]的最长公
共前缀的长度的最大值是多少?佳媛姐姐并不擅长做这样的问题,所以她向你求助,你该如何帮助她呢?

Input

输入的第一行有两个正整数n,m,分别表示字符串的长度和询问的个数。接下来一行是一个长为n的字符串。接下来
m行,每行有4个数a,b,c,d,表示询问s[a..b]的所有子串和s[c..d]的最长公共前缀的最大值。1<=n,m<=100,000,
字符串中仅有小写英文字母,a<=b,c<=d,1<=a,b,c,d<=n

Output

对于每一次询问,输出答案。

Sample Input

5 5
aaaaa
1 1 1 5
1 5 1 1
2 3 2 3
2 4 2 3
2 3 2 4

Sample Output

1
1
2
2
2
 
题解:
 真是太刺激了。。第一次发现后缀数组可以和高级数据结构联系起来233
(不过据说正解并不是裸跑后缀数组……)
首先,我们容易想到二分答案求解,但是二分之后怎么处理呢?
我们考虑,对于这个二分的长度x,rank[c]附近一定可以形成一段区间,使得他们的lcp大于等于x(rank[c]自己的lcp是串长)
这一段区间的查询我们可以通过ST表进行查询
接下来,如果[a,b]范围内有一个串存在于那个区间里就好了,
那么我们考虑,如何查询某个区间内的一些给定值是否出现某个值呢?
这种查询的特点不难让我们想到主席树"切割区间"的功能:
即查询a到b-x+1(如果x等于0,那么这个端点是b)区间内是否有一个rank值处在刚才查找到的区间,
我们可以通过主席树这种权值线段树记录这个存在性问题
这样不断判断合法性即可,复杂度是nlogn预处理+mlog2n查询的,因此可以AC.
代码实现:
 #include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int N=;
int cnt[N],xx[N],yy[N],n;
char s[N];
int rank[N],sa[N],height[N],bin[],f[N][];
inline void get_sa(int m)
{
int *x=xx,*y=yy;
register int i,j,p,k;
for(i=;i<m;++i)cnt[i]=;
for(i=;i<n;++i)++cnt[x[i]=s[i]];
for(i=;i<m;++i)cnt[i]+=cnt[i-];
for(i=n-;~i;--i)sa[--cnt[x[i]]]=i;
for(k=,p=;k<=n&&p<n;k<<=,m=p)
{
for(p=,i=n-k;i<n;++i)y[p++]=i;
for(i=;i<n;++i)if(sa[i]>=k)y[p++]=sa[i]-k;
for(i=;i<m;++i)cnt[i]=;
for(i=;i<n;++i)++cnt[x[y[i]]];
for(i=;i<m;++i)cnt[i]+=cnt[i-];
for(i=n-;~i;--i)sa[--cnt[x[y[i]]]]=y[i];
swap(x,y),x[sa[]]=,p=;
for(i=;i<n;++i)
x[sa[i]]=(y[sa[i]]==y[sa[i-]]&&y[sa[i]+k]==y[sa[i-]+k])?p-:p++;
}
}
inline void get_height()
{
register int i,j,k;
for(i=;i<n;++i)rank[sa[i]]=i;
for(k=i=;i<n;height[rank[i++]]=k)
for(k=k?k-:k,j=sa[rank[i]-];s[i+k]==s[j+k];++k);
}
inline void ST()
{
register int i,j;
for(bin[]=i=;i<=;++i)
bin[i]=bin[i-]<<;
for(j=;j<n;++j)f[j][]=height[j];
for(i=;bin[i-]<=n;++i)
for(j=;j+bin[i]<=n;++j)
f[j][i]=min(f[j][i-],f[j+bin[i-]][i-]);
}
struct node
{
node *ch[];int cnt;
node(){ch[]=ch[]=NULL;cnt=;}
inline void update(){cnt=ch[]->cnt+ch[]->cnt;}
}*null=new node(),*root[N];
inline node* newnode()
{node *o=new node();o->ch[]=o->ch[]=null;return o;}
inline bool query(node *a,node *b,int L,int R,int l,int r)
{
if(L<=l&&r<=R)return b->cnt-a->cnt;
int mi=l+r>>;bool ret=;
if(L<=mi)ret|=query(a->ch[],b->ch[],L,R,l,mi);
if(mi<R)ret|=query(a->ch[],b->ch[],L,R,mi+,r);
return ret;
}
inline void get_range(int val,int &l,int &r)
{
register int j;
for(j=;~j&&r<n;--j)
if(r+bin[j]-<n&&f[r+][j]>=val)r+=bin[j];
for(j=;~j&&l;--j)
if(l-bin[j]+>=&&f[l-bin[j]+][j]>=val)l-=bin[j];
}
inline bool judge(int a,int b,int c,int minimum)
{
int l=rank[c],r=rank[c],right=minimum?b-minimum+:b;
get_range(minimum,l,r);
if(query(a?root[a-]:null,root[right],l,r,,n-))return ;
return ;
}
inline void insert(node *&o,node *old,int l,int r,int pos)
{
o->cnt=old->cnt+;int mi=(l+r)>>;if(l==r)return;
if(pos<=mi)
o->ch[]=old->ch[],o->ch[]=newnode(),
insert(o->ch[],old->ch[],l,mi,pos);
else
o->ch[]=old->ch[],o->ch[]=newnode(),
insert(o->ch[],old->ch[],mi+,r,pos);
o->update();
}
inline void Tree_intn()
{
register int i;
null->ch[]=null->ch[]=null;
for(i=;i<n;++i)root[i]=newnode();
insert(root[],null,,n-,rank[]);
for(i=;i<n;++i)
insert(root[i],root[i-],,n-,rank[i]);
}
int main()
{
register int i,j,k,a,b,c,d,m,l,mi,r,ans;
scanf("%d%d%s",&n,&m,s),s[n++]=,
get_sa(),get_height(),ST(),Tree_intn();
while(m--)
{
scanf("%d%d%d%d",&a,&b,&c,&d),--a,--b,--c,--d;
l=,mi,r=min(b-a+,d-c+),ans=;
while(l<=r)
if(judge(a,b,c,(mi=l+r>>)))l=mi+,ans=mi;
else r=mi-;
printf("%d\n",ans);
}
}

[BZOJ4556][Tjoi2016&Heoi2016]字符串 后缀数组+主席树的更多相关文章

  1. BZOJ4556:[TJOI\HEOI2016]字符串(后缀数组,主席树,二分,ST表)

    Description 佳媛姐姐过生日的时候,她的小伙伴从某东上买了一个生日礼物.生日礼物放在一个神奇的箱子中.箱子外边写了一个长为n的字符串s,和m个问题.佳媛姐姐必须正确回答这m个问题,才能打开箱 ...

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

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

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

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

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

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

  5. [HEOI2016] 字符串 - 后缀数组,主席树,ST表,二分

    [HEOI2016] 字符串 Description 给定一个字符串 \(S\), 有 \(m\) 个询问,每个询问给定参数 \((a,b,c,d)\) ,求 \(s[a..b]\) 的子串与 \(s ...

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

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

  7. BZOJ 4556 [Tjoi2016&Heoi2016]字符串 ——后缀数组 ST表 主席树 二分答案

    Solution 1: 后缀数组暴力大法好 #include <map> #include <cmath> #include <queue> #include &l ...

  8. P4094 [HEOI2016/TJOI2016]字符串 后缀数组+主席树+二分答案

    $ \color{#0066ff}{ 题目描述 }$ 佳媛姐姐过生日的时候,她的小伙伴从某东上买了一个生日礼物.生日礼物放在一个神奇的箱子中.箱子外边写了一个长为n的字符串s,和m个问题.佳媛姐姐必须 ...

  9. BZOJ3473:字符串(后缀数组,主席树,二分,ST表)

    Description 给定n个字符串,询问每个字符串有多少子串(不包括空串)是所有n个字符串中至少k个字符串的子串? Input 第一行两个整数n,k. 接下来n行每行一个字符串. Output 一 ...

随机推荐

  1. 【日常训练】Help Victoria the Wise(Codeforces 99C)

    题意与分析 这题意思是这样的:在正方体的六面镶嵌给定颜色的宝石(相同颜色不区分),然后问最多有几种彼此不等价(即各种旋转过后看起来一致)的方案. 其实可以乱搞,因为范围只有720.求出全排列,然后每个 ...

  2. MySQL数据库引擎、事务隔离级别、锁

    MySQL数据库引擎.事务隔离级别.锁 数据库引擎InnoDB和MyISAM有什么区别 大体区别为: MyISAM类型不支持事务处理等高级处理,而InnoDB类型支持.MyISAM类型的表强调的是性能 ...

  3. 【转】sshpass-Linux命令之非交互SSH密码验证

      sshpass-Linux命令之非交互SSH密码验证 ssh登陆不能在命令行中指定密码.sshpass的出现,解决了这一问题.sshpass用于非交互SSH的密码验证,一般用在sh脚本中,无须再次 ...

  4. SQL注入原理&分类&危害&防御

    SQL是什么? 结构化查询语句 SQL注入是什么? 是一种将SQL 语句插入或添加到用户输入的参数中,这些参数传递到后台服务器,加以解析并执行 造成注入的原因/原理? 1.对用户输入的参数没有进行严格 ...

  5. websocket protocal

    same-orgins:浏览器同源策略的安全模型   持久化协议   双向双工  多路复用, 同时发信息   区别HTTP连接特点:  http只能由客户端发起,一个request对应一个respon ...

  6. Netty源码分析第4章(pipeline)---->第7节: 前章节内容回顾

    Netty源码分析第四章: pipeline 第七节: 前章节内容回顾 我们在第一章和第三章中, 遗留了很多有关事件传输的相关逻辑, 这里带大家一一回顾 首先看两个问题: 1.在客户端接入的时候, N ...

  7. Nginx笔记(一):安装

    Nginx在安装前需要先安装其所依赖的类库,所以需先行安装好之后再进行Nginx安装. Nginx依赖以下模块: l  gzip模块需要 zlib 库 l  rewrite模块需要 pcre 库 l  ...

  8. python os.walk详解

    os模块大全详情 os.walkos.walk方法,主要用来遍历一个目录内各个子目录和子文件. os.walk(top, topdown=True, onerror=None, followlinks ...

  9. 一个demo 理解 vuex

    相比接触vue的同学们已经看了官方文档了.这里我用一个简单的demo来阐述下vuex的知识点,虽然简单,但是容易理解.也加深自己的记忆. 用脚手架建立个项目vue init webpakc-simpl ...

  10. 微信小程序——节奏练耳 宣传页

    节奏练耳是什么? 节奏练耳小程序是一款听音练习节奏的交互式小程序.节奏练耳第一大节是辨认六种音符的练习,剩余九大节的练习题中播放的音频是将时值长短不一的音符组合在一起,配合相应的节奏图片,以提高辨认节 ...