「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. 数字IC设计入门书单

    首发于观芯志 写文章     数字IC设计入门书单 Forever snow   1 年前 作者:Forever snow链接:你所在领域的入门书单? - 知乎用户的回答来源:知乎著作权归作者所有,转 ...

  2. C# Test Encryption and Decryption

    public MainWindow() { InitializeComponent(); Title = getUUID(); string s= httpGet("http://220.1 ...

  3. 编程语法分析之“优先级”和“结合律”

    上节<编程语法分析之从表达式说起>中说到表达式,他的主要作用就是返回一个值!那这个值具体是多少,就要看表达式的整个运算过程.要理解表达式的运算过程就必须了解"优先级"和 ...

  4. Linux shell(5)

    shell程序流程控制的三大结构: 1. 顺序结构 2.选择结构 3.循环结构 顺序结构的定义: 顺序结构的程序设计是最简单的一种结构,它的执行顺序自上而下,依次执行,因此,我们只要按照解决问题的思路 ...

  5. Unity5.6之前版本VRTK插件基础交互

    一.VR运行环境配置: 安装steam,在steam上安装SteamVR驱动. 在Unity项目中需要导入VRTool插件包(已上传服务器),里面包含两个插件一个是SteamVR插件,一个是VRTK插 ...

  6. java 软件开发面试宝典

    一. Java 基础部分........................................................................................ ...

  7. 当activity改变时,我们如何处理它

    用户和系统触发­的事件,可能造成一个activity状体的改变.这个文档描述了一些常见的情况,和如何去处理这些改变. 原网站:https://developer.android.google.cn/g ...

  8. GTX1060 深度学习工具链

    通过试错,推荐GTX1060 WIN10的工具链记录如下: GPU: GTX 1060 6G OS: WIN10 CUDA:9.0 CuDNN:7.1.3 Tensorflow: Tensorflow ...

  9. ejs 模板使用方法

    http://embeddedjs.com/ Embedded JS Templates Embedded JS(EJS) 来源于ERB模板,且与ERB有很多相似之处.它有着与ERB相同的Tag,且包 ...

  10. PAT甲题题解-1014. Waiting in Line (30)-模拟,优先级队列

    题意:n个窗口,每个窗口可以排m人.有k为顾客需要办理业务,给出了每个客户的办理业务时间.银行在8点开始服务,如果窗口都排满了,客户就得在黄线外等候.如果有一个窗口用户服务结束,黄线外的客户就进来一个 ...