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 ...
随机推荐
- Codeforces Round #266 (Div. 2) C. Number of Ways
You've got array a[1], a[2], ..., a[n], consisting of n integers. Count the number of ways to split ...
- Win10 LTSB版本安装
win10 LTSB版本可以看作是 win10的阉割版,没有了几乎用不到还占资源的应用商店.小娜.没有了 EDGE只有IE11....云云 下载地址 https://msdn.itellyou.cn ...
- 【Nutch基础教程之七】Nutch的2种执行模式:local及deploy
在对nutch源码执行ant runtime后,会创建一个runtime的文件夹.在runtime文件夹下有deploy和local 2个文件夹. [jediael@jediael runtime]$ ...
- python实现QQ机器人(自己主动登录,获取群消息,发送群消息)
一次偶然的机会我看见了一个群里的一个QQ号总是依据你所发的消息自己主动回复,当时非常感觉到奇妙.我知道能够模拟登录站点,没想到居然也能模拟登录QQ,首先自己想到的就是怎样实现模拟登录PC端的QQ, 開 ...
- qt动画入门
Qt-4.6新增了Animation Framework(动画框架),让我们可以方便的写一些生动的程序. 不必像曾经的版本号一样,全部的控件都枯燥的呆在伟大光荣的QLayout里,或许它们可以唱个歌, ...
- 通过/proc/cpuinfo判断CPU数量、Multicores、Multithreading、Hyper-threading
http://blog.sina.com.cn/s/blog_4a6151550100iowl.html 判断依据:1.具有相同core id的cpu是同一个core的超线程.2.具有相同physic ...
- jsp学习笔记总结
Cookie中对保存对象的大小是有限制的 解决cookie中无法保存中文的问题: request.setCharacterEncoding URLEncoder.encode()编码 URLDecod ...
- hive:Access denied for user 'root'@'%'
配置hive全分布模式时候,在mysql里面创建用户:create user 'hive' identified by 'hive'; 然后给hive帐号分配全部权限: grant all privi ...
- AOP是怎么实现的,有几种方式
1.静态AOP:在编译期,切面直接以字节 码的形式编译到目标字节 码文件中. AspectJ属于静态AOP,是在编译时进行增强,会在编译的时候将AOP逻辑织入到代码中,需要专有的编译器和织入器. 优点 ...
- appium安装报错但运行成功
npm install -g appium ERR! fetch failed https://registry.npmjs.org/appium-uiauto/-/appium-uiauto-1. ...