「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. Swift图书展示项目笔记

    1.Swift语言特点 Extensions(扩展):就是向一个已有的类.结构体.枚举类型或者协议类型添加新功能.这包括在没有权限获取原始源代码的情况下扩展类型的能力(即逆向建模) map: 得到一个 ...

  2. javascript删除Cookie的正确方法(转载)

    原来一直以为只要设置javascript的document.cookie对象就能简单的在浏览器端设置和删除cookie值,网上很多文章也是这么教的,但是最近发现简单的设置javascript的docu ...

  3. jquery訪问ashx文件演示样例

    .ashx 文件用于写web handler的..ashx文件与.aspx文件类似,能够通过它来调用HttpHandler类,它免去了普通.aspx页面的控件解析以及页面处理的过程.事实上就是带HTM ...

  4. R 语言的Dataframe常用操作

    上节我们简单介绍了Dataframe的定义,这节我们具体来看一下Dataframe的操作 首先,数据框的创建函数为 data.frame( ),参考R语言的帮助文档,我们来了解一下data.frame ...

  5. # 2017-2018-2 20155319『网络对抗技术』Exp5:MSF基础应用

    2017-2018-2 20155319『网络对抗技术』Exp5:MSF基础应用 基础问题回答 用自己的话解释什么是exploit,payload,encode exploit:使用者利用漏洞进行攻击 ...

  6. 20155325 Exp4 恶意代码分析

    系统运行监控 (1)使用如计划任务,每隔一分钟记录自己的电脑有哪些程序在联网,连接的外部IP是哪里.运行一段时间并分析该文件,综述一下分析结果.目标就是找出所有连网的程序,连了哪里,大约干了什么(不抓 ...

  7. SQL调优日志--内存问题排查入门篇

    概述 很多系统的性能问题,是由内存导致的.内存不够会导致页面频繁换入换出,IO队列高,进而影响数据库整体性能. 排查 内存对数据库性能非常重要.那么我当出现问题的时候,我们怎么排查性能问题呢? 存在问 ...

  8. Android开发者不可或缺的四大工具

    Android开发者不可或缺的四大工具 android以其极强的开放性吸引着世界各地的开发者去开发各种各样的移动应用开发,而各种SDK更是为各个层次的开发者提供了一个可以尽情展示他们专业技能和创造性的 ...

  9. Windows Server 2003出现Directory Listing Denied This Virtual Directory does not allow contents to be listed.的解决方案

    Directory Listing DeniedThis Virtual Directory does not allow contents to be listed. 是目录权限无法访问的问题 解决 ...

  10. unity小地图制作___按比例尺图标布局

    1. 2.这里小地图显示的范围为整个空间区域,而不是单独的相机渲染区域 3. 4. 5. using System.Collections; using System.Collections.Gene ...