4556: [Tjoi2016&Heoi2016]字符串

链接

分析:

  首先可以二分这个长度。此时需要判断是否存在一个以b结尾的前缀,满足与[c,d]的lcp大于等于mid。

  如果我们把串翻转,那么就是判断是否存在一个以b开始的后缀,这样可以建出SAM,线段树维护每个点的right集合。此时在从包含[1,b]这个状态的点沿着parent树往上跳,那么长度会减少,相应的right集合会变大,于是可以跳到第一个长度满足的点,right集合也是满足的点中最大的,看这个点中是否存在[a,b-mid+1]的位置。

  SA的做法:求出height数组,二分一个长度mid,找到[c,d]的rnk设为p,从p往左往右找满足lcp长度都大于等于mid的区间[l,r],然后判断[l,r]中是否在[a,b-mid+1]中出现过。

代码:

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<iostream>
#include<cmath>
#include<cctype>
#include<set>
#include<queue>
#include<vector>
#include<map>
using namespace std;
typedef long long LL; inline int read() {
int x=,f=;char ch=getchar();for(;!isdigit(ch);ch=getchar())if(ch=='-')f=-;
for(;isdigit(ch);ch=getchar())x=x*+ch-'';return x*f;
} const int N = ; int ls[N * ], rs[N * ], Root[N], pos[N], ch[N][], len[N], fa[N], tmp[N], xl[N], f[N][];
int TreeIndex, Index = , Last = , n;
char s[N]; void Insert(int l,int r,int &now,int p) {
now = ++TreeIndex;
if (l == r) return ;
int mid = (l + r) >> ;
if (p <= mid) Insert(l, mid, ls[now], p);
else Insert(mid + , r, rs[now], p);
}
int query(int l,int r,int now,int L,int R) {
if (!now) return ;
if (L <= l && r <= R) return ;
int mid = (l + r) >> ;
if (L <= mid && query(l, mid, ls[now], L, R)) return ;
if (R > mid && query(mid + , r, rs[now], L, R)) return ;
return ;
}
int Merge(int x,int y) {
if (!x || !y) return x + y;
int z = ++TreeIndex;
ls[z] = Merge(ls[x], ls[y]);
rs[z] = Merge(rs[x], rs[y]);
return z;
}
void extend(int c,int i) {
int np = ++Index, p = Last; pos[i] = np; // pos[i] = np; !!!!!
len[np] = len[p] + ;
for (; p && !ch[p][c]; p = fa[p]) ch[p][c] = np;
if (!p) fa[np] = ;
else {
int q = ch[p][c];
if (len[q] == len[p] + ) fa[np] = q;
else {
int nq = ++Index;
memcpy(ch[nq], ch[q], sizeof(ch[q]));
fa[nq] = fa[q];
fa[np] = fa[q] = nq;
len[nq] = len[p] + ;
for (; p && ch[p][c] == q; p = fa[p]) ch[p][c] = nq;
}
}
Last = np;
Insert(, n, Root[np], i);
}
bool check(int mid,int x,int l,int r) {
for (int i = ; ~i; --i) if (len[f[x][i]] >= mid) x = f[x][i];
return query(, n, Root[x], l, r);
}
int main() {
n = read();int m = read();
scanf("%s", s + );
reverse(s + , s + n + );
for (int i = ; i <= n; ++i) extend(s[i] - 'a', i);
for (int i = ; i <= Index; ++i) tmp[len[i]] ++;
for (int i = ; i <= n; ++i) tmp[i] += tmp[i - ];
for (int i = Index; i >= ; --i) xl[tmp[len[i]]--] = i;
for (int i = Index; i > ; --i) {
int x = xl[i];
Root[fa[x]] = Merge(Root[fa[x]], Root[x]);
}
for (int i = ; i <= Index; ++i) f[i][] = fa[i];
for (int j = ; j <= ; ++j)
for (int i = ; i <= Index; ++i) f[i][j] = f[f[i][j - ]][j - ];
while (m --) {
int a = n - read() + , b = n - read() + , c = n - read() + , d = n - read() + ;
swap(a, b); swap(c, d);
int l = , r = min(d - c + , b - a + ), ans = ;
while (l <= r) {
int mid = (l + r) >> ;
if (check(mid, pos[d], a + mid - , b)) ans = mid, l = mid + ;
else r = mid - ;
}
printf("%d\n", ans);
}
return ;
}

4556: [Tjoi2016&Heoi2016]字符串的更多相关文章

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

随机推荐

  1. [WPF 容易忽视的细节] —— Exception in WPF's Converter

    前言: 在WPF中,Converter是我们经常要用到的一个工具,因为XAML上绑定的数据不一定是我们需要的数据. 问题: 在Converter中抛出一个异常导致程序崩溃,而且是在对未捕获异常进行集中 ...

  2. java中Proxy(代理与动态代理)

    转自: https://blog.csdn.net/pangqiandou/article/details/52964066 一.代理的概念 动态代理技术是整个java技术中最重要的一个技术,它是学习 ...

  3. 文档撰写思路与排版(hadoop)

    这几天在写项目提交的几个报告,写完回想了一下,在写作框架确定与排版上浪费了不少时间,特此总结一下思路. 这个写完回家过年了....emmmm 1. 定好大标题框架,使用自动添加序号,先不着急修改样式 ...

  4. 从专用磁盘创建 Windows VM

    通过使用 Powershell 将专用托管磁盘附加为 OS 磁盘来创建新 VM. 专用磁盘是保留原始 VM 中的用户帐户.应用程序和其他状态数据的现有 VM 中虚拟硬盘 (VHD) 的副本. 使用专用 ...

  5. 【SVN】Linux下svn搭建配置全过程——初学者轻松上手篇

    版本控制主要用到的是git和svn,其中svn界面化使用操作简单,本篇简单介绍SVN搭建配置全过程. 1. 下载并安装 yum install subversion 查看版本 svnserve --v ...

  6. WLW/OLW 最佳博客写作软件

    前言 我发布到博客园中文章大多是通过Windows live Writer(wlw)来写的,本文记录一下wlw的安装及快捷键. WLW博客园插入代码插件:http://www.cnblogs.com/ ...

  7. 自己动手制作一个本地的yum仓库

    制作本地yum源有两种方式,第一种是使用光盘镜像,然后在本地进行安装.第二种是我们自己创建一个本地yum仓库,然后使用file的形式来向本地提供yum repo(也可以使用http的方式向外部提供,我 ...

  8. console.time方法与console.timeEnd方法

    在Node.js中,当需要统计一段代码的执行时间时,可以使用console.time方法与console.timeEnd方法,其中console.time方法用于标记开始时间,console.time ...

  9. Universal-Image-Loader源码分析(二)——载入图片的过程分析

    之前的文章,在上面建立完config之后,UIl通过ImageLoader.getInstance().init(config.build());来初始化ImageLoader对象,之后就可以用Ima ...

  10. BZOJ3155:Preprefix sum(线段树)

    Description Input 第一行给出两个整数N,M.分别表示序列长度和操作个数 接下来一行有N个数,即给定的序列a1,a2,....an 接下来M行,每行对应一个操作,格式见题目描述 Out ...