「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. 【LeetCode7】Reverse Integer★

    题目描述: 解题思路: 反转的方法很简单,重点在于判断溢出的问题,下面给出了两种方法. Java代码: 方法一: 判断溢出方法:在执行完int newResult=result*10+tail语句后, ...

  2. SEO优化上首页之搜索引擎排名规则

    搜索引擎建立索引的网页数以万亿计,用户搜索的关键词也是海量,如果每个用户提交搜索请求后,搜索引擎都去数以万亿的索引中重新排名网页,效率将非常低下.根据2-8法则,80%是查询是集中在相同的20%内容上 ...

  3. MySQL 数据库赋予用户权限操作表

    MySQL清空数据库的操作:truncate table tablename; MySQL 赋予用户权限命令的简单格式可概括为:grant 权限 on 数据库对象 to 用户  一.grant 普通数 ...

  4. 20155202 张旭《网络对抗》Exp2 后门原理与实践

    20155202 张旭<网络对抗>Exp2 后门原理与实践 基础问题回答 例举你能想到的一个后门进入到你系统中的可能方式? 捆绑在软件中 注入在可执行文件里 注入在office文件的宏里面 ...

  5. 20155235 《网络攻防》 实验八 Web基础

    20155235 <网络攻防> 实验八 Web基础 实验内容 Web前端HTML(0.5分) 能正常安装.启停Apache.理解HTML,理解表单,理解GET与POST方法,编写一个含有表 ...

  6. 2017-2018-2 20155315《网络对抗技术》Exp9 :Web安全基础

    实验目的 理解常用网络攻击技术的基本原理. 教程1 教程2 教程3 实验内容 SQL注入攻击 XSS攻击 CSRF攻击 Webgoat前期准备 从GitHub上下载jar包 拷贝到本地,并使用命令ja ...

  7. 20155318 《网络攻防》Exp5 MSF基础应用

    20155318 <网络攻防>Exp5 MSF基础应用 基础问题 用自己的话解释什么是exploit,payload,encode? exploit就相当于是载具,将真正要负责攻击的代码传 ...

  8. 20155333 《网络对抗》Exp2 后门原理与实践

    20155333 <网络对抗>Exp2 后门原理与实践 1.例举你能想到的一个后门进入到你系统中的可能方式? 下载的软件中捆绑有后门: 浏览的网页或其上的小广告: 有些网页会自动安装软件. ...

  9. mfc 嵌套类

    嵌套类 一. 嵌套类 嵌套类的定义 将某个类的定义放在另一个类的内部,这样的类定义,叫嵌套类. class AAA { int aaa; class BBB { int bbb; //其它成员或者函数 ...

  10. 【个人】爬虫实践,利用xpath方式爬取数据之爬取虾米音乐排行榜

    实验网站:虾米音乐排行榜 网站地址:http://www.xiami.com/chart  难度系数:★☆☆☆☆ 依赖库:request.lxml的etree (安装lxml:pip install ...