bzoj4556
后缀自动机+二分+倍增+线段树合并
后缀自动机真好用
后面一个串是固定的,那么我们要对前面的串进行一些操作。我们想既然是求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的更多相关文章
- 【BZOJ4556】字符串(后缀数组,主席树)
[BZOJ4556]字符串(后缀数组,主席树) 题面 BZOJ 题解 注意看题: 要求的是\([a,b]\)的子串和[c,d]的\(lcp\)的最大值 先来一下暴力吧 求出\(SA\)之后 暴力枚举\ ...
- BZOJ4556 [Tjoi2016&Heoi2016]字符串 SA ST表 二分答案 主席树
原文链接https://www.cnblogs.com/zhouzhendong/p/BZOJ4556.html 题目传送门 - BZOJ4556 题意 给定一个长度为 $n$ 的字符串 $s$ . ...
- 【BZOJ4556】[Tjoi2016&Heoi2016]字符串 后缀数组+二分+主席树+RMQ
[BZOJ4556][Tjoi2016&Heoi2016]字符串 Description 佳媛姐姐过生日的时候,她的小伙伴从某东上买了一个生日礼物.生日礼物放在一个神奇的箱子中.箱子外边写了一 ...
- [BZOJ4556][TJOI2016&&HEOI2016]字符串(二分答案+后缀数组+RMQ+主席树)
4556: [Tjoi2016&Heoi2016]字符串 Time Limit: 20 Sec Memory Limit: 128 MBSubmit: 1360 Solved: 545[S ...
- BZOJ4556: [Tjoi2016&Heoi2016]字符串
Description 佳媛姐姐过生日的时候,她的小伙伴从某东上买了一个生日礼物.生日礼物放在一个神奇的箱子中.箱子外边写了 一个长为n的字符串s,和m个问题.佳媛姐姐必须正确回答这m个问题,才能打开 ...
- Bzoj4556: [Tjoi2016&Heoi2016]字符串 后缀数组
4556: [Tjoi2016&Heoi2016]字符串 Time Limit: 20 Sec Memory Limit: 128 MBSubmit: 169 Solved: 87[Sub ...
- 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... ...
- bzoj4556(sam)
二分答案,(具体可见http://blog.csdn.net/neither_nor/article/details/51669114),然后就是判定问题,sa和sam都可以做,用sam写了一下,先用 ...
- BZOJ4556:[TJOI\HEOI2016]字符串(后缀数组,主席树,二分,ST表)
Description 佳媛姐姐过生日的时候,她的小伙伴从某东上买了一个生日礼物.生日礼物放在一个神奇的箱子中.箱子外边写了一个长为n的字符串s,和m个问题.佳媛姐姐必须正确回答这m个问题,才能打开箱 ...
- BZOJ4556 HEOI2016字符串
没错,又是这题,使用后缀自动机,反向建树,主席树维护right集合. By:大奕哥 #include<bits/stdc++.h> using namespace std; ; ]; ch ...
随机推荐
- Java对象的死亡
在堆里面存放着Java世界中几乎所有的对象实例,垃圾收集器在对堆进行回收前,第一件事情就是要确定这些对象之中哪些还“存活”着,哪些已经“死去”(即不可能再被任何途径使用的对象). 一,引用计数算法 给 ...
- Android Studio一些常用的快捷键
光标移动和窗口切换:1.esc:光标从功能窗口回到编辑窗口 2.alt+num:打开指定的功能窗口,重复操作关闭该窗口. 3.alt+←→:切换编辑的文件. 4.ctrl+home/end:跳转到文件 ...
- 如何在ASP.NET Core自定义中间件中读取Request.Body和Response.Body的内容?
原文:如何在ASP.NET Core自定义中间件中读取Request.Body和Response.Body的内容? 文章名称: 如何在ASP.NET Core自定义中间件读取Request.Body和 ...
- keras常见问题解答
https://keras.io/zh/getting-started/faq/ https://keras.io/zh/ https://github.com/keras-team/keras/tr ...
- Python基础语法04-数据结构
Python Number(数字) Python Number 数据类型用于存储数值. 数据类型是不允许改变的,这就意味着如果改变 Number 数据类型的值,将重新分配内存空间. Python 支持 ...
- chrome 的onbeforeunload事件没有触发
onbeforeunload event is not working when user not click inside the body of page 0down votefavorite ...
- insserv: warning: script 'lampp' missing LSB tags and overrides
https://ubuntuforums.org/showthread.php?t=2327011 1.方法一,编辑rc.loacl脚本 Ubuntu开机之后会执行/etc/rc.local文件中的脚 ...
- springboot mybatis 项目框架源码 shiro 集成代码生成器 ehcache缓存
1.代码生成器: [正反双向](单表.主表.明细表.树形表,快速开发利器)freemaker模版技术 ,0个代码不用写,生成完整的一个模块,带页面.建表sql脚本.处理类.service等完整模块2. ...
- java学习笔记(四)面向对象
一.形參长度可变的方法 当传入被调用的函数參数数量不确定时,在方法最后一个形參的类型后加上三个点号(...),表明该形參能够接受多个參数值.多个參数值被当做数组传入,这些參数必须为指定的类型. pac ...
- docker 搭建linux samba
https://hub.docker.com/r/jenserat/samba-publicshare/ 需要共享目录 只需直接 挂载容器映射即可