后缀自动机+二分+倍增+线段树合并

后缀自动机真好用

后面一个串是固定的,那么我们要对前面的串进行一些操作。我们想既然是求lcp,那么我们得先翻转原串,这样前缀变成了后缀,然后二分一下,从d在自动机上的位置向上倍增,走到第一个Max大于当前答案的位置,用线段树合并判断一下当前是否满足。还是很好写的,具体看代码。注意线段树合并必须新开一个节点。

#include<bits/stdc++.h>
using namespace std;
const int N = 2e5 + ;
int n, m;
int fa[N][], mp[N << ];
vector<int> G[N];
namespace Segment_Tree
{
int cnt;
int root[N], sum[N * ], lc[N * ], rc[N * ];
void update(int &x, int l, int r, int p, int d)
{
x = ++cnt;
sum[x] += d;
if(l == r) return;
int mid = (l + r) >> ;
if(p <= mid) update(lc[x], l, mid, p, d);
else update(rc[x], mid + , r, p, d);
}
int merge(int u, int v)
{
if(!u) return v;
if(!v) return u;
int w = ++cnt;
sum[w] = sum[u] + sum[v];
lc[w] = merge(lc[u], lc[v]);
rc[w] = merge(rc[u], rc[v]);
return w;
}
int query(int x, int l, int r, int a, int b)
{
if(!x || l > b || r < a) return ;
if(l >= a && r <= b) return sum[x];
int mid = (l + r) >> ;
return (query(lc[x], l, mid, a, b) + query(rc[x], mid + , r, a, b));
}
} using namespace Segment_Tree;
namespace SAM
{
struct node {
int val, par;
int ch[];
} t[N];
int sz = , Root = , last = ;
int nw(int x)
{
t[++sz].val = x;
return sz;
}
void extend(int c)
{
int p = last, np = nw(t[p].val + );
while(p && !t[p].ch[c]) t[p].ch[c] = np, p = t[p].par;
if(!p) t[np].par = Root;
else
{
int q = t[p].ch[c];
if(t[q].val == t[p].val + ) t[np].par = q;
else
{
int nq = nw(t[p].val + );
memcpy(t[nq].ch, t[q].ch, sizeof(t[q].ch));
t[nq].par = t[q].par;
t[q].par = t[np].par = nq;
while(p && t[p].ch[c] == q) t[p].ch[c] = nq, p = t[p].par;
}
}
last = np;
mp[t[np].val] = np;
update(root[np], , n, t[np].val, );
}
void dfs(int u)
{
for(int i = ; i < G[u].size(); ++i)
{
int v = G[u][i];
fa[v][] = u;
dfs(v);
root[u] = merge(root[u], root[v]);
}
}
} using namespace SAM;
char s[N];
bool check(int len, int l, int r, int u)
{
for(int i = ; i >= ; --i)
if(t[fa[u][i]].val >= len)
u = fa[u][i];
// if(t[u].val < len) return 0;
return query(root[u], , n, l + len - , r);
}
int main()
{
// freopen("heoi2016_str.in", "r", stdin);
// freopen("heoi2016_str.out", "w", stdout);
scanf("%d%d%s", &n, &m, s + );
reverse(s + , s + n + );
for(int i = ; i <= n; ++i) extend(s[i] - 'a');
for(int i = ; i <= sz; ++i) G[t[i].par].push_back(i);
dfs(Root);
for(int j = ; j <= ; ++j)
for(int i = ; i <= sz; ++i)
fa[i][j] = fa[fa[i][j - ]][j - ];
while(m--)
{
int a, b, c, d, ta, tb, tc, td;
scanf("%d%d%d%d", &ta, &tb, &tc, &td);
a = n - tb + ;
b = n - ta + ;
c = n - td + ;
d = n - tc + ;
int l = , r = min(b - a + , d - c + ), ans = ;
while(r - l > )
{
int mid = (l + r) >> ;
if(check(mid, a, b, mp[d])) l = ans = mid;
else r = mid;
}
printf("%d\n", ans);
}
// fclose(stdin);
// fclose(stdout);
return ;
}

bzoj4556的更多相关文章

  1. 【BZOJ4556】字符串(后缀数组,主席树)

    [BZOJ4556]字符串(后缀数组,主席树) 题面 BZOJ 题解 注意看题: 要求的是\([a,b]\)的子串和[c,d]的\(lcp\)的最大值 先来一下暴力吧 求出\(SA\)之后 暴力枚举\ ...

  2. BZOJ4556 [Tjoi2016&Heoi2016]字符串 SA ST表 二分答案 主席树

    原文链接https://www.cnblogs.com/zhouzhendong/p/BZOJ4556.html 题目传送门 - BZOJ4556 题意 给定一个长度为 $n$ 的字符串 $s$ . ...

  3. 【BZOJ4556】[Tjoi2016&Heoi2016]字符串 后缀数组+二分+主席树+RMQ

    [BZOJ4556][Tjoi2016&Heoi2016]字符串 Description 佳媛姐姐过生日的时候,她的小伙伴从某东上买了一个生日礼物.生日礼物放在一个神奇的箱子中.箱子外边写了一 ...

  4. [BZOJ4556][TJOI2016&&HEOI2016]字符串(二分答案+后缀数组+RMQ+主席树)

    4556: [Tjoi2016&Heoi2016]字符串 Time Limit: 20 Sec  Memory Limit: 128 MBSubmit: 1360  Solved: 545[S ...

  5. BZOJ4556: [Tjoi2016&Heoi2016]字符串

    Description 佳媛姐姐过生日的时候,她的小伙伴从某东上买了一个生日礼物.生日礼物放在一个神奇的箱子中.箱子外边写了 一个长为n的字符串s,和m个问题.佳媛姐姐必须正确回答这m个问题,才能打开 ...

  6. Bzoj4556: [Tjoi2016&Heoi2016]字符串 后缀数组

    4556: [Tjoi2016&Heoi2016]字符串 Time Limit: 20 Sec  Memory Limit: 128 MBSubmit: 169  Solved: 87[Sub ...

  7. 2019.02.27 bzoj4556: [Tjoi2016&Heoi2016]字符串(二分答案+sam+线段树合并)

    传送门 题意:给一个字符串SSS. 有mmm次询问,每次给四个参数a,b,c,da,b,c,da,b,c,d,问s[a...b]s[a...b]s[a...b]的所有子串和s[x...y]s[x... ...

  8. bzoj4556(sam)

    二分答案,(具体可见http://blog.csdn.net/neither_nor/article/details/51669114),然后就是判定问题,sa和sam都可以做,用sam写了一下,先用 ...

  9. BZOJ4556:[TJOI\HEOI2016]字符串(后缀数组,主席树,二分,ST表)

    Description 佳媛姐姐过生日的时候,她的小伙伴从某东上买了一个生日礼物.生日礼物放在一个神奇的箱子中.箱子外边写了一个长为n的字符串s,和m个问题.佳媛姐姐必须正确回答这m个问题,才能打开箱 ...

  10. BZOJ4556 HEOI2016字符串

    没错,又是这题,使用后缀自动机,反向建树,主席树维护right集合. By:大奕哥 #include<bits/stdc++.h> using namespace std; ; ]; ch ...

随机推荐

  1. Java对象的死亡

    在堆里面存放着Java世界中几乎所有的对象实例,垃圾收集器在对堆进行回收前,第一件事情就是要确定这些对象之中哪些还“存活”着,哪些已经“死去”(即不可能再被任何途径使用的对象). 一,引用计数算法 给 ...

  2. Android Studio一些常用的快捷键

    光标移动和窗口切换:1.esc:光标从功能窗口回到编辑窗口 2.alt+num:打开指定的功能窗口,重复操作关闭该窗口. 3.alt+←→:切换编辑的文件. 4.ctrl+home/end:跳转到文件 ...

  3. 如何在ASP.NET Core自定义中间件中读取Request.Body和Response.Body的内容?

    原文:如何在ASP.NET Core自定义中间件中读取Request.Body和Response.Body的内容? 文章名称: 如何在ASP.NET Core自定义中间件读取Request.Body和 ...

  4. keras常见问题解答

    https://keras.io/zh/getting-started/faq/ https://keras.io/zh/ https://github.com/keras-team/keras/tr ...

  5. Python基础语法04-数据结构

    Python Number(数字) Python Number 数据类型用于存储数值. 数据类型是不允许改变的,这就意味着如果改变 Number 数据类型的值,将重新分配内存空间. Python 支持 ...

  6. chrome 的onbeforeunload事件没有触发

    onbeforeunload event is not working when user not click inside the body of page 0down votefavorite   ...

  7. insserv: warning: script 'lampp' missing LSB tags and overrides

    https://ubuntuforums.org/showthread.php?t=2327011 1.方法一,编辑rc.loacl脚本 Ubuntu开机之后会执行/etc/rc.local文件中的脚 ...

  8. springboot mybatis 项目框架源码 shiro 集成代码生成器 ehcache缓存

    1.代码生成器: [正反双向](单表.主表.明细表.树形表,快速开发利器)freemaker模版技术 ,0个代码不用写,生成完整的一个模块,带页面.建表sql脚本.处理类.service等完整模块2. ...

  9. java学习笔记(四)面向对象

    一.形參长度可变的方法 当传入被调用的函数參数数量不确定时,在方法最后一个形參的类型后加上三个点号(...),表明该形參能够接受多个參数值.多个參数值被当做数组传入,这些參数必须为指定的类型. pac ...

  10. docker 搭建linux samba

    https://hub.docker.com/r/jenserat/samba-publicshare/ 需要共享目录 只需直接 挂载容器映射即可