4556: [Tjoi2016&Heoi2016]字符串
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]字符串的更多相关文章
- Bzoj 4556: [Tjoi2016&Heoi2016]字符串
4556: [Tjoi2016&Heoi2016]字符串 Time Limit: 20 Sec Memory Limit: 128 MBSubmit: 177 Solved: 92[Sub ...
- BZOJ 4556: [Tjoi2016&Heoi2016]字符串(后缀数组 + 二分答案 + 主席树 + ST表 or 后缀数组 + 暴力)
题意 一个长为 \(n\) 的字符串 \(s\),和 \(m\) 个询问.每次询问有 \(4\) 个参数分别为 \(a,b,c,d\). 要你告诉它 \(s[a...b]\) 中的所有子串 和 \(s ...
- ●BZOJ 4556 [Tjoi2016&Heoi2016]字符串
题链: http://www.lydsy.com/JudgeOnline/problem.php?id=4556 题解: 巨恶心...但是题很好呀,可以练习好几个比较麻烦的算法~ 1).预处理 首先用 ...
- bzoj 4556 [Tjoi2016&Heoi2016]字符串——后缀数组+主席树
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=4556 本来只要查 ht[ ] 数组上的前驱和后继就行,但有长度的限制.可以二分答案解决!然后 ...
- BZOJ 4556 [Tjoi2016&Heoi2016]字符串 ——后缀数组 ST表 主席树 二分答案
Solution 1: 后缀数组暴力大法好 #include <map> #include <cmath> #include <queue> #include &l ...
- Bzoj4556: [Tjoi2016&Heoi2016]字符串 后缀数组
4556: [Tjoi2016&Heoi2016]字符串 Time Limit: 20 Sec Memory Limit: 128 MBSubmit: 169 Solved: 87[Sub ...
- [BZOJ4556][Tjoi2016&Heoi2016]字符串 后缀数组+主席树
4556: [Tjoi2016&Heoi2016]字符串 Time Limit: 20 Sec Memory Limit: 128 MB Description 佳媛姐姐过生日的时候,她的小 ...
- [BZOJ4556][TJOI2016&&HEOI2016]字符串(二分答案+后缀数组+RMQ+主席树)
4556: [Tjoi2016&Heoi2016]字符串 Time Limit: 20 Sec Memory Limit: 128 MBSubmit: 1360 Solved: 545[S ...
- [BZOJ4556][Tjoi2016&Heoi2016]字符串 主席树+二分+倍增+后缀自动机
4556: [Tjoi2016&Heoi2016]字符串 Time Limit: 20 Sec Memory Limit: 128 MBSubmit: 1215 Solved: 484[S ...
随机推荐
- C#把Xml转换为DataSet的两种方法
转:https://blog.csdn.net/beyondqd/article/details/6724676 下面给出两个实现XML数据转成DataSet的两个方法. 第1种: //通过传入的特定 ...
- c#中Indexof()和Split()的用法
C#中IndexOf的使用 indexOf() 查找字串中指定字符或字串首次出现的位置,返首索引值,如: str1.IndexOf("字"): //查找“字”在str1中的索引值( ...
- Oracle EBS OPM release step
--release_step生产批 --created by jenrry SET serveroutput on DECLARE x_return_status VARCHAR2 (1); l_ex ...
- 【转】Linux下从TCP状态机,三次握手判断DDOS攻击
从TCP状态机判断DDOS攻击 一.TCP协议 TCP 协议是传送层的核心协议,提供了可靠面向连接的协议,分为三次握手和四次断开,在这个过程中TCP有个状态机,记录不同阶段的状态. 二. TCP握手和 ...
- TiDB数据库集群安装以及注意事项
今天尝试安装tidb集群.详细的安装步骤我们参考:https://pingcap.com/docs-cn/op-guide/ansible-deployment/ . 不过安装之前需要一些注意事项. ...
- BZOJ3632:外太空旅行(最大团,DFS)
Description 在人类的触角伸向银河系的边缘之际,普通人上太空旅行已经变得稀松平常了.某理科试验班有n个人,现在班主任要从中选出尽量多的人去参加一次太空旅行活动. 可是n名同学并不是和平相处的 ...
- 欢迎来到Curl的世界
一.Curl 简介 curl命令是一个利用URL规则在命令行下工作的文件传输工具.它支持文件的上传和下载,所以是 综合传输工具,但按传统,习惯称curl为下载工具.作为一款强力工具,curl支持包括H ...
- shiro实战系列(一)之入门实战
一.什么是shiro? Apache Shiro 是一个强大而灵活的开源安全框架,它干净利落地处理身份认证,授权,企业会话管理和加密. Apache Shiro 的首要目标是易于使用和理解.安全有 ...
- 无法找到“XXX.exe”的调试信息,或者调试信息不匹配。未使用调试信息生成二进制文件
1.问题症状 已经处于Debug模式,运行时完全正常,但是一调试就出现对话框,显示出错信息:“无法找到“XXX.exe”的调试信息,或者调试信息不匹配.未使用调试信息生成二进制文件.” 2.解决方法 ...
- Python2.7-ConfigParser
ConfigParser模块,用于读写配置文件,配置文件是由各个 section 组成的,每个部分都有一个 [section] 头指示,后面紧跟这部分里的配置信息,一般为 name: value 或 ...