[HEOI2016/TJOI2016]字符串 (后缀数组+主席树+二分)

description

佳媛姐姐过生日的时候,她的小伙伴从某东上买了一个生日礼物。生日礼物放在一个神奇的箱子中。箱子外边写了一个长为 n 的字符串 s,和 m 个问题。佳媛姐姐必须正确回答这 m 个问题,才能打开箱子拿到礼物,升职加薪,出任 CEO,嫁给高富帅,走上人生巅峰。每个问题均有 a,b,c,d 四个参数,问你子串
s[a…b] 的所有子串和 s[c…d]的最长公共前缀的长度的最大值是多少?佳媛姐姐并不擅长做这样的问题,所以她向你求助,你该如何帮助她呢?

输入格式
输入的第一行有两个正整数 n,m,分别表示字符串的长度和询问的个数。
接下来一行是一个长为 n 的字符串。字符串中仅有小写英文字母。
接下来 m 行,每行有四个数 a,b,c,d,表示询问 s[a…b] 的所有子串和 s[c…d]的最长公共前缀的最大值

输出格式
对于每一次询问,输出答案

样例

5 5
aaaaa
1 1 1 5
1 5 1 1
2 3 2 3
2 4 2 3
2 3 2 41
1
2
2
2

数据范围与提示
对于所有的数据,1≤n,m≤100000, a≤b, c≤d, 1≤a,b,c,d≤n

solution

S[a:b]S[a:b]S[a:b]所有子串和S[c:d]S[c:d]S[c:d]整串的最长公共前缀


Step1
二分。。。
如果一个长度midmidmid可行,那么比midmidmid小的所有长度也都可行
即决策具有单调性,可以二分


Step2
如果二分的长度midmidmid可行,则这个串必然满足

  1. 开头端点在[a,b−mid+1][a,b-mid+1][a,bmid+1]
  2. LCP(s,c)≥midLCP(s,c)\ge midLCP(s,c)mid

Step3
最长公共前缀,无脑上后缀数组,用RMQRMQRMQ查询LCPLCPLCP


Step4
步骤二转化为二元限制问题
解决方案:摁死一元,logloglog另一元
将后缀数组的rankrankrank排序后建立主席树,查找区间[a,b−mid+1][a,b-mid+1][a,bmid+1]
rankrankrank建立主席树是由于其LCPLCPLCP的特殊性质决定的
LCPLCPLCP满足条件的一定是一个连续区间,再套用二分,二分出区间的左右端点


code

#include <cmath> 
#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;
#define INF 0x7f7f7f7f
#define maxn 100005
struct node {int l, r, sum;
}t[maxn << 5];
int n, m = 255, Q, cnt;
int tot[maxn], sa[maxn], x[maxn], id[maxn], rnk[maxn << 1], h[maxn], root[maxn];
int st[maxn][25];
char s[maxn];void read( int &x ) {int f = 1;x = 0;char s = getchar();while( s < '0' || s > '9' ) {if( s == '-' ) f = -1;s = getchar();}while( '0' <= s && s <= '9' ) {x = ( x << 1 ) + ( x << 3 ) + ( s - '0' );s = getchar(); }x *= f;
}void print( int x ) {if( x < 0 ) putchar( '-' ), x = -x;if( x > 9 ) print( x / 10 );putchar( x % 10 + '0' );
}void suffix() {for( int i = 1;i <= n;i ++ ) tot[x[i] = s[i]] ++;for( int i = 1;i <= m;i ++ ) tot[i] += tot[i - 1];for( int i = n;i;i -- ) sa[tot[x[i]] --] = i;for( int k = 1;k <= n;k <<= 1 ) {int num = 0;for( int i = n - k + 1;i <= n;i ++ ) id[++ num] = i;for( int i = 1;i <= n;i ++ ) if( sa[i] > k ) id[++ num] = sa[i] - k;memset( tot, 0, sizeof( tot ) );for( int i = 1;i <= n;i ++ ) tot[x[i]] ++;for( int i = 1;i <= m;i ++ ) tot[i] += tot[i - 1];for( int i = n;i;i -- ) sa[tot[x[id[i]]] --] = id[i];for( int i = 1;i <= n;i ++ ) rnk[i] = x[i];x[sa[1]] = num = 1;for( int i = 2;i <= n;i ++ )x[sa[i]] = ( rnk[sa[i]] == rnk[sa[i - 1]] && rnk[sa[i] + k] == rnk[sa[i - 1] + k] ) ? num : ++ num;if( n == num ) break;m = num;}	
}void height() {for( int i = 1;i <= n;i ++ ) rnk[sa[i]] = i;int k = 0;for( int i = 1;i <= n;i ++ ) {if( rnk[i] == 1 ) continue;if( k ) k --;int j = sa[rnk[i] - 1];while( i + k <= n && j + k <= n && s[i + k] == s[j + k] ) k ++;h[rnk[i]] = k;}
}void RMQ() {for( int i = 1;i <= n;i ++ ) st[i][0] = h[i];for( int j = 1;j <= 20;j ++ )for( int i = 1;i <= n;i ++ )if( i + ( 1 << j - 1 ) > n ) break;else st[i][j] = min( st[i][j - 1], st[i + ( 1 << j - 1 )][j - 1] );
}int lcp( int l, int r ) { //左闭右闭rmqif( l > r ) return INF;int i = log( r - l + 1 ) / log( 2 );return min( st[l][i], st[r - ( 1 << i ) + 1][i] );	
}void insert( int pre, int &now, int l, int r, int pos ) {if( ! now ) now = ++ cnt;if( l == r ) {t[now].sum = t[pre].sum + 1;return;}int mid = ( l + r ) >> 1;if( pos <= mid ) {t[now].r = t[pre].r;insert( t[pre].l, t[now].l, l, mid, pos );}else {t[now].l = t[pre].l;insert( t[pre].r, t[now].r, mid + 1, r, pos );}t[now].sum = t[t[now].l].sum + t[t[now].r].sum;
}int query( int pre, int now, int l, int r, int L, int R ) {if( t[now].sum - t[pre].sum == 0 ) return 0;if( L <= l && r <= R ) return t[now].sum - t[pre].sum;int mid = ( l + r ) >> 1, tot = 0;if( L <= mid ) tot += query( t[pre].l, t[now].l, l, mid, L, R );if( mid < R ) tot += query( t[pre].r, t[now].r, mid + 1, r, L, R );return tot;
}int main() {read( n ), read( Q );scanf( "%s", s + 1 );suffix();height();RMQ();for( int i = 1;i <= n;i ++ )insert( root[i - 1], root[i], 1, n, rnk[i] );for( int i = 1, a, b, c, d;i <= Q;i ++ ) {read( a ), read( b ), read( c ), read( d );int l = 0, r = min( b - a + 1, d - c + 1 ), ans;while( l <= r ) {//二分最后的LCP答案长度midint mid = ( l + r ) >> 1, range_l, range_r, L, R;//符合要求的子串的rank一定与c连在一起[rnk[c]-t1,rnk[c]+t2]L = 1, R = rnk[c];//二分找前缀t1 贪心越往前肯定mid越可能成立while( L <= R ) {int MID = ( L + R ) >> 1;if( lcp( MID + 1, rnk[c] ) >= mid ) range_l = MID, R = MID - 1;else L = MID + 1;}L = rnk[c], R = n;//二分找后缀t2 贪心越往后肯定mid越可能成立while( L <= R ) {int MID = ( L + R ) >> 1;if( lcp( rnk[c] + 1, MID ) >= mid ) range_r = MID, L = MID + 1;else R = MID - 1;}//只要在[a,b-mid+1]内存在任意一个即说明mid成立if( query( root[a - 1], root[b - mid + 1], 1, n, range_l, range_r ) ) ans = mid, l = mid + 1;else r = mid - 1;}print( ans ), puts( "" );}return 0;
} 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/317581.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

[SDOI2014]旅行

[SDOI2014]旅行 题意&#xff1a; n个城市&#xff0c;n-1条边&#xff0c;任意两个城市互通&#xff0c;每个城市有所信奉的宗教和城市评级&#xff0c;有四种指令&#xff1a; 1.将城市x的居民改信为c教 2.将城市x的评级调整为w 3.统计x到y&#xff0c;路上所有的城市的评级…

YbtOJ-染色计划【树链剖分,线段树,tarjan】

正题 题目大意 给出nnn个点的一棵树&#xff0c;每个点有个颜色aia_iai​&#xff0c;你每次可以选择一个颜色全部变成另一个颜色。 求最少多少次操作可以把一种颜色变成一个完整的连通块。 1≤k≤n≤21051\leq k\leq n\leq 2\times 10^51≤k≤n≤2105 解题思路 考虑如果我们…

张高兴的 .NET Core IoT 入门指南:环境配置、Blink、部署

如何在 Raspberry Pi 的 Raspbian 上构建使用 GPIO 引脚的 IoT 程序&#xff1f;你可能会回答使用 C 或 Python 去访问 Raspberry Pi 的引脚。现在&#xff0c;C# 程序员可以使用 .NET Core 在 Raspbian(Linux) 上构建 IoT 应用程序。只需要引入 System.Device.GPIONuGet 包即可…

CF183C:Diverse Permutation(构造)

解析 首先考虑如何构造kn-1的情况 发现令排列为1,n,2,n-1…即可 那么在k不等于n-1时 只需要让前k项与上面的序列相同&#xff0c;后面公差为1即可 代码 #include<bits/stdc.h> using namespace std; #define ll long long #define ull unsigned long long const int N…

CF603E-Pastoral Oddities【CDQ分治,可撤销并查集】

正题 题目链接:https://www.luogu.com.cn/problem/CF603E 题目大意 开始时有nnn个点&#xff0c;没有边。 依次加入mmm条带权的边&#xff0c;每次加入后询问是否存在一个边集&#xff0c;满足每个点的度数均为奇数&#xff0c;求使得这个边集的最大权值最小。 1≤n≤105,1≤…

2020ICPC 江西省大学生程序设计竞赛

2020ICPC 江西省大学生程序设计竞赛

在AspNetMvc中使用日志面板. Logdashboard 1.1beta

Logdashboard是Net下的日志面板,它支持AspNet与AspNetCore项目。关于更多LogDashboard的介绍请看这里--使用logdashboard查看可视化日志。就在刚刚LogDashboard发布了1.1的beta版,在这个版本中有以下变化https://github.com/liangshiw/LogDashboard/releases支持NetFramework的…

【正睿2021寒假省选第二轮集训 day 1】令牌生成 (组合数+二分)

description solution 打表yyds 其实符合条件的个数跟nnn&#xff08;非题目中的意思&#xff09;有着等差数列公式的千丝万缕关系 所以可以二分出具体值 最后答案的取值范围一定是长成[,)[,)[,)&#xff0c;左闭右开的形式的 而且两个边界一定是只差了最小的那个111&#xff…

CF600F:Edge coloring of bipartite graph(二分图、构造)

解析 首先大胆猜结论&#xff1a;答案就是最大的点度数 考虑如何构造 设一个点联通的边的颜色集合为S&#xff0c;由题意得S中的元素不可重 假设新加入一条边(u,v) 设c1mex(Su),c2mex(Sv)c1mex(S_u),c2mex(S_v)c1mex(Su​),c2mex(Sv​) 如果c1等于c2&#xff0c;直接连就行了…

CF464E-The Classic Problem【最短路,主席树】

正题 题目链接:https://www.luogu.com.cn/problem/CF464E 题目大意 nnn个点mmm条边的一张无向图&#xff0c;第iii条边长度为2xi2^{x_i}2xi​&#xff0c;求sss到ttt的最短路。 1≤n≤105,0≤m,xi≤1051\leq n\leq 10^5,0\leq m,x_i\leq 10^51≤n≤105,0≤m,xi​≤105 解题思路…

.NETStandard FreeSql v0.0.9 功能预览

年关将至&#xff0c;首页技术含量文章真是越来越少&#xff0c;理解大家盼着放假过年&#xff0c;哥们我何尝不是&#xff0c;先给大家拜个早年。兄弟我从11月底发了神经&#xff0c;开启了 ORM 功能库的开发之旅&#xff0c;历时两个月编码和文档整理&#xff0c;目前预览版本…

【CF868F】Yet Another Minimization Problem (决策单调性优化dp+分治)

description 点击查看题目 solution code 设dpi,jdp_{i,j}dpi,j​&#xff1a;把前iii个数划分jjj段的最小花费&#xff0c;wi,jw_{i,j}wi,j​&#xff1a;[i,j][i,j][i,j]划分为一段的花费 dpi,jmin(dp[k][j−1]w[k1][i])&#xff0c;k<idp_{i,j}min(dp[k][j-1]w[k1][i…

YbOJ-网格序列【拉格朗日插值】

正题 题目大意 有一个nmn\times mnm的网格&#xff0c;在上面填上[1,k][1,k][1,k]的数字&#xff0c;定义两个长度为nnn的序列ai,bia_i,b_iai​,bi​分别表示每一行/每一列的最大值。 求有多少种不同的合法a,ba,ba,b对。 1≤n,m≤106,1≤k≤1091\leq n,m\leq 10^6,1\leq k\le…

CF720C Homework(构造)(暴力)

解析 本题的关键是暴力与构造结合的思想 本题一排排往上填的想法不难得出&#xff0c;但是在列数较小的时候就会GG 所以考虑在n>5&#xff0c;m<5时&#xff0c;交换n&#xff0c;m&#xff0c;显然问题还是等价的 如果nm均小于5&#xff0c;就直接暴力dfs解决 在最后的…

第十二届蓝桥杯C++赛后感

文章目录A 空间卡片直线货物摆放路径时间显示G砝码称重H杨辉三角形双向排列J括号序列注&#xff1a;有些代码忘了考试时怎么写的了&#xff0c;&#xff08;我也懒得重新写&#xff09;&#xff0c;所以很多题的代码是acwing蓝桥杯讲解里的&#xff0c;我对其进行注释和修改A 空…

SeaweedFS在.net core下的实践方案

一直对分布式的文件储存系统很感兴趣&#xff0c;最开始关注淘宝的TFS&#xff08;Taobao File System&#xff09;&#xff0c;好像搁浅了&#xff0c;官方地址无法访问&#xff0c;github上面&#xff0c;各种编译问题&#xff0c;无意间发现了SeaweedFS链接seaweedfs测试了一…

[C++ STL algorithm] lower_bound、upper_bound、unique的本质

lower_bound&#xff1a;返回第一个大于等于查找值的地址upper_bound&#xff1a;返回第一个严格大于查找值的地址 使用这两个函数需要的头文件 #include <algorithm> using namespace std;要求数组必须是有序/单调的 lower_bound lower_bound( a 1, a n 1, x );意…

蓝桥杯 I.双向排序

题目链接 题解&#xff1a; 比赛时就直接写了一个暴力sort交上&#xff0c;能骗一点分是一点 昨晚看了acwing的讲解&#xff0c;现在结合我的思路更新正解 题目中设计两个操作&#xff0c;一个是选定前x个数&#xff0c;使其降序&#xff0c;另一个是选定后y个数&#xff0c…

YbtOJ-交换游戏【树链剖分,线段树合并】

正题 题目大意 给出两棵树&#xff0c;对于第一棵树的每一条边(x,y)(x,y)(x,y)询问有多少条在第二棵树上的边(u,v)(u,v)(u,v)与其交换&#xff08;连接的序号相同&#xff09;后两棵树依旧是一棵树。 1≤n≤21051\leq n\leq 2\times 10^51≤n≤2105 解题思路 先只考虑一棵树的…

模板:树状数组二分

所谓树状数组二分&#xff0c;就是在树状数组上进行二分 &#xff08;逃&#xff09; 解析 很巧妙 我们都知道可以在线段树上利用其本身平衡二叉的性质进行二分&#xff0c;很多时候能剩下一个log 但是树状数组其实也是可以二分的 说是二分&#xff0c;其实更像倍增 毕竟不…