[题目链接]

https://www.lydsy.com/JudgeOnline/problem.php?id=4556

[算法]

不难发现 , 对于每个询问
        ans = max{ min{b - i + 1 , lcp(i , c) } (a <= i <= b)

不妨二分答案mid , 那么问题就转化为求 max{ lcp(i  , c) } (a <= i <= b - mid + 1)

而我们知道 , 所有lcp(i , j) <= k的i是连续的一段区间

可以再次通过二分求出这个区间

问题又转化为判断[a , b - mid + 1]中是否有rank值在区间[L , R]中的数

构建出后缀数组 , 主席树维护rank值即可

时间复杂度 : O(NlogN ^ 2)

[代码]

#include<bits/stdc++.h>
using namespace std;
const int N = 1e5 + ;
const int MAXLOG = ;
typedef long long ll;
typedef long double ld;
typedef unsigned long long ull; #define rint register int int n , m;
int rk[N] , rt[N] , sa[N] , cnt[N] , height[N] , lg[N];
int val[N][MAXLOG];
char s[N]; struct Presitent_Segment_Tree
{
int sz;
int lc[N * ] , rc[N * ] , cnt[N * ];
Presitent_Segment_Tree()
{
sz = ;
}
inline void build(int &now , int l , int r)
{
now = ++sz;
if (l == r) return;
int mid = (l + r) >> ;
build(lc[now] , l , mid);
build(rc[now] , mid + , r);
}
inline void modify(int &now , int old , int l , int r , int x , int value)
{
now = ++sz;
lc[now] = lc[old] , rc[now] = rc[old];
cnt[now] = cnt[old] + value;
if (l == r) return;
int mid = (l + r) >> ;
if (mid >= x) modify(lc[now] , lc[old] , l , mid , x , value);
else modify(rc[now] , rc[old] , mid + , r , x , value);
}
inline bool query(int rt1 , int rt2 , int l , int r , int ql , int qr)
{
if (ql > qr || cnt[rt1] - cnt[rt2] == )
return false;
if (l == ql && r == qr)
return (cnt[rt1] - cnt[rt2] > );
int mid = (l + r) >> ;
if (mid >= qr) return query(lc[rt1] , lc[rt2] , l , mid , ql , qr);
else if (mid + <= ql) return query(rc[rt1] , rc[rt2] , mid + , r , ql , qr);
else return query(lc[rt1] , lc[rt2] , l , mid , ql , mid) | query(rc[rt1] , rc[rt2] , mid + , r , mid + , qr);
}
} PST;
template <typename T> inline void chkmax(T &x,T y) { x = max(x,y); }
template <typename T> inline void chkmin(T &x,T y) { x = min(x,y); }
template <typename T> inline void read(T &x)
{
T f = ; x = ;
char c = getchar();
for (; !isdigit(c); c = getchar()) if (c == '-') f = -f;
for (; isdigit(c); c = getchar()) x = (x << ) + (x << ) + c - '';
x *= f;
}
inline void build_sa()
{
static int x[N] , y[N];
memset(cnt , , sizeof(cnt));
for (rint i = ; i <= n; i++) ++cnt[(int)s[i]];
for (rint i = ; i <= ; i++) cnt[i] += cnt[i - ];
for (rint i = n; i >= ; i--) sa[cnt[(int)s[i]]--] = i;
rk[sa[]] = ;
for (rint i = ; i <= n; i++) rk[sa[i]] = rk[sa[i - ]] + (s[sa[i]] != s[sa[i - ]]);
for (rint k = ; rk[sa[n]] != n; k <<= )
{
for (rint i = ; i <= n; i++)
x[i] = rk[i] , y[i] = (i + k <= n) ? rk[i + k] : ;
memset(cnt , , sizeof(cnt));
for (rint i = ; i <= n; i++) ++cnt[y[i]];
for (rint i = ; i <= n; i++) cnt[i] += cnt[i - ];
for (rint i = n; i >= ; i--) rk[cnt[y[i]]--] = i;
memset(cnt , , sizeof(cnt));
for (rint i = ; i <= n; i++) ++cnt[x[i]];
for (rint i = ; i <= n; i++) cnt[i] += cnt[i - ];
for (rint i = n; i >= ; i--) sa[cnt[x[rk[i]]]--] = rk[i];
rk[sa[]] = ;
for (rint i = ; i <= n; i++) rk[sa[i]] = rk[sa[i - ]] + (x[sa[i]] != x[sa[i - ]] || y[sa[i]] != y[sa[i - ]]);
}
}
inline void get_height()
{
int k = ;
for (rint i = ; i <= n; i++)
{
if (k) --k;
int j = sa[rk[i] - ];
while (s[i + k] == s[j + k]) ++k;
height[rk[i]] = k;
}
}
inline void rmq_init()
{
for (rint i = ; i <= n; i++)
val[i][] = height[i];
for (rint j = ; ( << j) <= n; j++)
{
for (rint i = ; i + ( << j) - <= n; i++)
{
val[i][j] = min(val[i][j - ] , val[i + ( << (j - ))][j - ]);
}
}
}
inline int query(int x , int y)
{
if (x > y) return ;
int k = lg[y - x + ];
return min(val[x][k] , val[y - ( << k) + ][k]);
} int main()
{ scanf("%d%d" , &n , &m);
scanf("%s" , s + );
build_sa();
get_height();
rmq_init();
PST.build(rt[] , , n);
for (rint i = ; i <= n; i++) PST.modify(rt[i] , rt[i - ] , , n , rk[i] , );
for (rint i = ; i <= n; i++) lg[i] = (double)(log(i) / log(2.0));
while (m--)
{
int a , b , c , d;
read(a); read(b); read(c); read(d);
int l = , r = min(d - c + , b - a + ) , ans = ;
while (l <= r)
{
int mid = (l + r) >> ;
int ll = , rr = rk[c] - , L = rk[c] , R = rk[c];
while (ll <= rr)
{
int md = (ll + rr) >> ;
if (query(md + , rk[c]) >= mid)
{
L = md;
rr = md - ;
} else ll = md + ;
}
ll = rk[c] + , rr = n , R = rk[c];
while (ll <= rr)
{
int md = (ll + rr) >> ;
if (query(rk[c] + , md) >= mid)
{
R = md;
ll = md + ;
} else rr = md - ;
}
if (PST.query(rt[b - mid + ] , rt[a - ] , , n , L , R))
{
l = mid + ;
ans = mid;
} else r = mid - ;
}
printf("%d\n" , ans);
} return ; }

[TJOI2016 & HEOI2016] 字符串的更多相关文章

  1. Bzoj 4556: [Tjoi2016&Heoi2016]字符串

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

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

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

  3. 4556: [Tjoi2016&Heoi2016]字符串

    4556: [Tjoi2016&Heoi2016]字符串 链接 分析: 首先可以二分这个长度.此时需要判断是否存在一个以b结尾的前缀,满足与[c,d]的lcp大于等于mid. 如果我们把串翻转 ...

  4. [BZOJ4556][Tjoi2016&Heoi2016]字符串 后缀数组+主席树

    4556: [Tjoi2016&Heoi2016]字符串 Time Limit: 20 Sec  Memory Limit: 128 MB Description 佳媛姐姐过生日的时候,她的小 ...

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

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

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

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

  7. [BZOJ4556][Tjoi2016&Heoi2016]字符串 主席树+二分+倍增+后缀自动机

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

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

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

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

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

  10. 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... ...

随机推荐

  1. 实机桌面上给虚拟机安装系统(分区,恢复GHO)

    在虚拟机里安装系统大家都会了.我这里介绍一种方法无须进入虚拟机里操作.全部在实机里完成对虚拟机安装系统(分区.恢复GHO).这里要使用到的工具如下1分区工具DISKGENIUS2虚拟光驱3Ghost镜 ...

  2. Geometry Shader 【转】

    Geometry shader – receives as its input complete primitives as a collection of vertices, and these i ...

  3. Go语言阅读小笔记,来自知呼达达关于unsafe.Pointer的分享.

    第一式 - 获得Slice和String的内存数据 func stringPointer(s string) unsafe.Pointer { p := (*reflect.StringHeader) ...

  4. vue native

    1.示例 <el-icon icon="Setting" size="sm" @click.native="ceshi">< ...

  5. 树状数组求最大值 (RMQ with Shifts)

    代码: #include <iostream> #include <stdio.h> #include <string.h> #include <stdlib ...

  6. mysql存储过程之循环

    链接: http://www.blogjava.net/rain1102/archive/2011/05/16/350301.html

  7. Django缓存问题

    由于Django是动态网站,所有每次请求均会去数据进行相应的操作,当程序访问量大时,耗时必然会更加明显,最简单解决方式是使用:缓存,缓存将一个某个views的返回值保存至内存或者memcache中,5 ...

  8. 关于error:Cannot assign to &#39;self&#39; outside of a method in the init family

    有时候我们重写父类的init方法时不注意将init后面的第一个字母写成了小写.在这种方法里面又调用父类的初始化方法(self = [super init];)时会报错,错误信息例如以下:error:C ...

  9. 数据库MySQL经典面试题之SQL语句

    数据库MySQL经典面试题之SQL语句 1.需要数据库表1.学生表Student(SID,Sname,Sage,Ssex) --SID 学生编号,Sname 学生姓名,Sage 出生年月,Ssex 学 ...

  10. 在Livemedia的基础上开发自己的流媒体客户端 V 0.01

    在Livemedia的基础上开发自己的流媒体客户端 V 0.01 桂堂东 xiaoguizi@gmail.com 2004-10 2004-12 友情申明: 本文档适合已经从事流媒体传输工作或者对网络 ...