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

后缀自动机真好用

后面一个串是固定的,那么我们要对前面的串进行一些操作。我们想既然是求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. 关于linter

    各类代码都有规则格式检查工具,称之为linter 比如:csslint/jslint/eslint/pylint sumlime提供了一个linter的框架SublimeLinter,在里面可以使用各 ...

  2. 配置 yum 源相关

    1. 修改yum配置 http://www.cnblogs.com/shuaixf/archive/2011/11/30/2268496.html 2. centos安装 epel 源 https:/ ...

  3. Linux下Tomcat VM參数改动

    不可行的方法 最初我直接改动catalina.sh, 将JAVA_OPTS变量加上了 -server -Xms1G -Xmx1G -XX:+UserG1GC 最初看起来没啥问题,可是当服务器运行几天后 ...

  4. 初探STL之算法

    算法 STL算法部分主要由头文件<algorithm>,<numeric>,<functional>组成.要使用 STL中的算法函数必须包括头文件<algor ...

  5. 生活娱乐 360安全卫士和QQ大战

    360安全卫士指控QQ侵犯用户隐私 [提要]9月26日晚上11点16分,安全软件商360在他们的论坛中发布了最新公告:<360安全卫士发布隐私保护器 专门曝光"窥私"软件&g ...

  6. SolidEdge如何在零件上写字 如何绘制文字

    在草图状态下,插入-文字轮廓   可以按这两个按钮调节文字的大小和位置   之后你可以通过长出或除料把文字凸起或者凹下去   如果你要制作路径文字(比如环形文字),则先绘制一条圆或一段圆弧,并设为构造 ...

  7. EF使用自定义字符串连接数据库

    edmx的构造函数: public TestCheckUpdatesEntities(): base(Config.DataBaseConnectionString(), "TestChec ...

  8. php闭包实例

    php闭包函数,一个典型的实例 function getMoney() { $rmb = 1; $dollar = 6; $func = function($dollar) use (&$rm ...

  9. addEventListener event

    addEventListener   先看个例子: document.getElementById("myBtn").addEventListener("click&qu ...

  10. 对交换机VLAN及各种端口类型的理解

    每学习一种技术时,我们往往需要去了解why,即这个技术是为解决什么问题而出现的. VLAN全称为Virtual Local Area Network,即虚拟局域网,是逻辑上的一种划分.一般来说,如果交 ...