「TJOI / HEOI2016」字符串

题目描述

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

\(1 \leq n, m \leq 100000, \ a \leq b, \ c \leq d, \ 1 \leq a, b, c, d \leq n\)

### 解题思路 :

写\(sam\)是肯定会去写的,这样才学的了字符串,后缀数组又不会用,\(sam\)套上数据结构的感觉就像回家一样

里面又能剖分又能线段树合并,调试又好调,我爱死这种写法了 \(qwq\)

问题求一个字符串的前缀最多能和另一个字符串的所有子串匹配多少, 不妨二分答案判断这个前缀是否在这些子串里出现过

考虑对母串建 \(sam\) ,求出原串中每一个后缀在 \(sam\) 上的对应节点,那么对于需要\(check\) 的前缀 \([c, c + len -1]\) ,可以快速倍增找到其在前缀树上对应的节点

设找到的节点为 \(u\) ,问题就转化为 \(u\) 的 \(right\) 集合中,是否存在一个来自于 \([a+len-1, b]\) 的后缀

所以,直接大力线段树合并维护 \(parent\) 树上每个节点的 \(right\) 集合即可,查询只需要判断对应线段树的 \([a+len-1, b]\) 的和是否 \(>=1\),复杂度是 \(O(mlog^2n)\)

/*program by mangoyang*/
#include<bits/stdc++.h>
#define inf (0x7f7f7f7f)
#define Max(a, b) ((a) > (b) ? (a) : (b))
#define Min(a, b) ((a) < (b) ? (a) : (b))
#define N (200005)
typedef long long ll;
using namespace std;
template <class T>
inline void read(T &x){
int f = 0, ch = 0; x = 0;
for(; !isdigit(ch); ch = getchar()) if(ch == '-') f = 1;
for(; isdigit(ch); ch = getchar()) x = x * 10 + ch - '0';
if(f) x = -x;
}
char s[N]; int n, m;
struct Segment_Tree{
int sum[N*25], lc[N*25], rc[N*25], cnt;
inline void modify(int &u, int l, int r, int pos){
u = ++cnt;
if(l == r) return (void) (sum[u]++);
int mid = l + r >> 1;
if(pos <= mid) modify(lc[u], l, mid, pos);
else modify(rc[u], mid + 1, r, pos);
sum[u] = sum[lc[u]] + sum[rc[u]];
}
inline int merge(int x, int y, int l, int r){
if(!x || !y) return x + y; int o = ++cnt;
if(l == r) sum[o] = sum[x] + sum[y];
else{
int mid = l + r >> 1;
lc[o] = merge(lc[x], lc[y], l, mid);
rc[o] = merge(rc[x], rc[y], mid + 1, r);
sum[o] = sum[lc[o]] + sum[rc[o]];
}
return o;
}
inline int query(int u, int l, int r, int L, int R){
if(!u) return 0;
if(l >= L && r <= R) return sum[u];
int mid = l + r >> 1, res = 0;
if(L <= mid) res += query(lc[u], l, mid, L, R);
if(mid < R) res += query(rc[u], mid + 1, r, L, R);
return res;
}
}Seg;
struct Suffix_Automaton{
int f[N][23], rt[N<<1], buf[N], a[N];
int ch[N][26], fa[N], dep[N], pos[N], tail, size;
inline Suffix_Automaton(){ tail = size = 1; }
inline int newnode(int x){ dep[++size] = x; return size; }
inline void ins(int c, int id){
int p = tail, np = newnode(dep[p] + 1);
Seg.modify(rt[np], 1, n, id), pos[id] = np;
for(; p && !ch[p][c]; p = fa[p]) ch[p][c] = np;
if(!p) return (void) (fa[np] = 1, tail = np);
int q = ch[p][c];
if(dep[q] == dep[p] + 1) fa[np] = q;
else{
int nq = newnode(dep[p] + 1);
fa[nq] = fa[q], fa[q] = fa[np] = nq;
for(int i = 0; i < 26; i++) ch[nq][i] = ch[q][i];
for(; p && ch[p][c] == q; p = fa[p]) ch[p][c] = nq;
}tail = np;
}
inline void prepare(){
for(int i = 1; i <= size; i++) f[i][0] = fa[i];
for(int j = 1; j <= 22; j++)
for(int i = 1; i <= size; i++) f[i][j] = f[f[i][j-1]][j-1];
for(int i = 1; i <= size; i++) buf[dep[i]]++;
for(int i = 1; i <= size; i++) buf[i] += buf[i-1];
for(int i = 1; i <= size; i++) a[buf[dep[i]]--] = i;
for(int i = size; i >= 2; i--){
int u = a[i];
rt[fa[u]] = Seg.merge(rt[u], rt[fa[u]], 1, n);
}
}
inline bool check(int x, int len, int l, int r){
x = pos[x];
for(int i = 22; i >= 0; i--) if(dep[f[x][i]] >= len) x = f[x][i];
return Seg.query(rt[x], 1, n, l, r) >= 1;
}
}van;
inline int solve(int a, int b, int c, int d){
int l = 1, r = min(b - a + 1, d - c + 1), ans = 0;
while(l <= r){
int mid = l + r >> 1;
if(van.check(c + mid - 1, mid, a + mid - 1, b))
ans = mid, l = mid + 1;
else r = mid - 1;
}
return ans;
}
int main(){
read(n), read(m), scanf("%s", s + 1);
for(int i = 1; i <= n; i++) van.ins(s[i] - 'a', i);
van.prepare();
for(int i = 1; i <= m; i++){
int a, b, c, d;
read(a), read(b), read(c), read(d);
printf("%d\n", solve(a, b, c, d));
}
return 0;
}

「TJOI / HEOI2016」字符串的更多相关文章

  1. loj#2059. 「TJOI / HEOI2016」字符串 sam+线段树合并+倍增

    题意:给你一个子串,m次询问,每次给你abcd,问你子串sa-b的所有子串和子串sc-d的最长公共前缀是多长 题解:首先要求两个子串的最长公共前缀就是把反过来插入变成最长公共后缀,两个节点在paren ...

  2. 【LOJ】#2059. 「TJOI / HEOI2016」字符串

    题解 我们冷静一下,先画一棵后缀树 然后发现我们要给c和d这一段区间在[a,b]这一段开头的串里找lcp 而lcp呢,就是c点的祖先的到根的一段,假如这个祖先的子树里有[a,b - dis[u] + ...

  3. loj2059 「TJOI / HEOI2016」字符串

    字符串好难啊不会啊 #include <iostream> #include <cstdio> using namespace std; int n, m, rnk[10000 ...

  4. loj#2054. 「TJOI / HEOI2016」树

    题目链接 loj#2054. 「TJOI / HEOI2016」树 题解 每次标记覆盖整棵字数,子树维护对于标记深度取max dfs序+线段树维护一下 代码 #include<cstdio> ...

  5. AC日记——#2054. 「TJOI / HEOI2016」树

    #2054. 「TJOI / HEOI2016」树 思路: 线段树: 代码: #include <cstdio> #include <cstring> #include < ...

  6. AC日记——#2057. 「TJOI / HEOI2016」游戏 LOJ

    #2057. 「TJOI / HEOI2016」游戏 思路: 最大流: 代码: #include <cstdio> #include <cstring> #include &l ...

  7. loj #2055. 「TJOI / HEOI2016」排序

    #2055. 「TJOI / HEOI2016」排序   题目描述 在 2016 年,佳媛姐姐喜欢上了数字序列.因而他经常研究关于序列的一些奇奇怪怪的问题,现在他在研究一个难题,需要你来帮助他. 这个 ...

  8. loj2058 「TJOI / HEOI2016」求和 NTT

    loj2058 「TJOI / HEOI2016」求和 NTT 链接 loj 思路 \[S(i,j)=\frac{1}{j!}\sum\limits_{k=0}^{j}(-1)^{k}C_{j}^{k ...

  9. LOJ #2058「TJOI / HEOI2016」求和

    不错的推柿子题 LOJ #2058 题意:求$\sum\limits_{i=0}^n\sum\limits_{j=0}^nS(i,j)·2^j·j!$其中$ S(n,m)$是第二类斯特林数 $ Sol ...

随机推荐

  1. Vue 项目集合

    饿了么安全应急响应中心 饿了么招聘 饿了么前端 · GitHub 稀土掘金 异乡好居 明星垂搜 广州建管 基于Vue.js的数据统计系统(一) 基于Vue.js的数据统计系统(二) 基于Vue.js的 ...

  2. JSON传输数组的基本操作

    目标JSON结果如下: 生成JSON的的过程如下: Document document; Document::AllocatorType& allocator = document.GetAl ...

  3. 如何写论文的introduction

    重要的是写Introduction.写Introduction就和写童话一样.(转自知乎珵cici) 1. 有一条巨龙抓走了公主 (介绍你的问题为什么值得研究) 2. 巨龙是多么多么多么难打(强调你的 ...

  4. [BZOJ4851][JSOI2016]位运算[矩阵快速幂]

    题意 给定长度为 \(\rm |S|\) 的 \(\rm 01\) 串并将其倍长 \(k\) 次得到一个 \(\rm|S|\times k\) 位的二进制数 \(R\) ,求有多少种在 \([0,R- ...

  5. Python 学习 第三篇:数组类型(列表、字典和元组)

    列表和字段都可以在原处进行修改,可以按照需求增长或缩短,并且可以包含任何类型的对象或被嵌套.列表和字典存储的是对象的引用,而不是拷贝. 一,列表 列表是有序的序列,每一个列表项的顺序是固定的,这使得列 ...

  6. 微服务监控zipkin、skywalking以及日志ELK监控系列

    0.整体架构 整体架构目录:ASP.NET Core分布式项目实战-目录 一.目录 1.zipkin监控 2.skywalking监控 3.ELK日志监控 asp.net Core 交流群:78746 ...

  7. 蓝牙学习笔记三(Android Debug)

    android 端可以通过两种方式去Debug: 一.在手机的设置功能里,开发者模式 Enable,如下图:   http://blog.bluetooth.com/debugging-bluetoo ...

  8. stl源码剖析 详细学习笔记 空间配置器

    //---------------------------15/04/05---------------------------- /* 空间配置器概述: 1:new操作包含两个阶段操作 1>调 ...

  9. Asp.Net_Get跟Post

    1. Get(即使用QueryString显式传递)     方式:在url后面跟参数.     特点:简单.方便.     缺点:字符串长度最长为255个字符:数据泄漏在url中.     适用数据 ...

  10. 32bit 天堂2脚本修改资料大全【客户端+服务端】

    该资料夹中所有教程资料全部适合天堂2初章32位服务端的脚本修改,已经1.2章相关客户端的修改. https://pan.baidu.com/s/1RuGMFNgERd2JMYQpdceQwg 提取码: ...