换markdown写了。。

题意:

给你一个1e5的字符串,1e5组询问,求\([l_1,r_1]\)的所有子串与\([l_2,r_2]\)的lcp

思路:

首先可以发现答案是具有单调性的,我们考虑二分答案,二分的范围显然为\([0,min(r_2-l_2+1,r_1-l_1+1)]\)

对于二分到的字符串长度mid,可以知道它的开头一定在\([l_1,r_1-mid+1]\)中,这样满足了限定条件

于是我们可以通过检查\([l_1,r_1-mid+1]\)中是否有个值p,使得\(lcp(rk[p],rk[l_2]) \geq mid\)即可判断答案

法一:

由\(lcp(i,j)=min(height[k]),i+1\leq k \leq j\)(i,j为排名)可知

为了使\(lcp(rk[p],rk[l2])\)尽量满足条件,rk[p]一定是目标区间内,\(rk[l_2]\)的前驱或后继

这样我们可以对(i,rk[i])建主席树,每次check查询\([l_1,r_1-mid+1]\)里\(rk[l_2]\)的前驱后继

但是问题来了,主席树查询前驱后继会退化。。(我乱讲的,可能是我不会写)

虽然在bzoj上跑了16s过了,但是这显然不优秀

update:退化的问题已经解决了:权值线段树剪枝的误解--以HDU6703为例

代码:

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<string>
#include<stack>
#include<queue>
#include<deque>
#include<set>
#include<vector>
#include<map> #define fst first
#define sc second
#define pb push_back
#define mem(a,b) memset(a,b,sizeof(a))
#define lson l,mid,root<<1
#define rson mid+1,r,root<<1|1
#define lc root<<1
#define rc root<<1|1
#define lowbit(x) ((x)&(-x)) using namespace std; typedef double db;
typedef long double ldb;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int> PI;
typedef pair<ll,ll> PLL; const db eps = 1e-6;
const int mod = 1e9+7;
const int maxn = 2e5+100;
const int maxm = 2e6+100;
const int inf = 0x3f3f3f3f;
const db pi = acos(-1.0); int n,m;
char s[maxn];
int sa[maxn],rk[maxn],height[maxn];
int y[maxn],x[maxn],c[maxn];
void getSa(){
for(int i=1;i<=n;i++)++c[x[i]=s[i]];
for(int i=2;i<=m;i++)c[i]+=c[i-1];
for(int i=n;i>=1;i--)sa[c[x[i]]--]=i;
for(int k=1;k<=n;k<<=1){
int num = 0;
for(int i=n-k+1;i<=n;i++)y[++num]=i;
for(int i=1;i<=n;i++)if(sa[i]>k)y[++num]=sa[i]-k;
for(int i=1;i<=m;i++)c[i]=0;
for(int i=1;i<=n;i++)++c[x[i]];
for(int i=2;i<=m;i++)c[i]+=c[i-1];
for(int i=n;i>=1;i--)sa[c[x[y[i]]]--]=y[i],y[i]=0;
swap(x,y);
x[sa[1]]=1;
num=1;
for(int i=2;i<=n;i++){
x[sa[i]]=(y[sa[i]]==y[sa[i-1]]&&y[sa[i]+k]==y[sa[i-1]+k])?num:++num;
}
if(num==n)break;
m=num;
}
}
void getHeight(){
int k=0;
for(int i=1; i<=n; ++i)rk[sa[i]]=i;
for(int i=1; i<=n; ++i){
if(rk[i]==1) continue;
if(k)--k;
int j=sa[rk[i]-1];
while(j+k<=n&&i+k<=n&&s[i+k]==s[j+k])++k;
height[rk[i]]=k;
}
}
int d[maxn][26];
void init(){
for(int i = 1; i <= n; i++) d[i][0]=height[i];
for(int j = 1; (1<<j) <= n; j++){
for(int i = 1; i + (1<<j) - 1 <= n; i++){
d[i][j] = min(d[i][j-1], d[i + (1<<(j-1))][j-1]);
}
}
}
int rmq(int l, int r){
if(l>r)return -1;
int k = 0;
while((1<<(k+1)) <= r-l+1)k++;
return min(d[l][k], d[r-(1<<k)+1][k]);
}
int q; int tot,root[maxn];
int dat[maxn*40],ls[maxn*40],rs[maxn*40];
int insert(int now, int l, int r, int x, int val){
int p = ++tot;
dat[p]=dat[now];ls[p]=ls[now];rs[p]=rs[now];
if(l==r){dat[p]+=val;return p;}
int mid = (l+r)>>1;
if(x<=mid)ls[p]=insert(ls[now],l,mid,x,val);
else rs[p]=insert(rs[now],mid+1,r,x,val);
dat[p]=dat[ls[p]]+dat[rs[p]];
return p;
}
int askmx(int x, int y, int l, int r, int k){//return rk|-1
int sumr = dat[rs[y]]-dat[rs[x]];
int mid = (l+r)>>1;
if(dat[y]-dat[x]==0)return -1;
if(l==r) return l;
if(mid<k){
int lRes = askmx(rs[x],rs[y],mid+1,r,k);
if(lRes==-1)lRes=askmx(ls[x],ls[y],l,mid,k);
return lRes;
}
else return askmx(ls[x],ls[y],l,mid,k); }
int askmi(int x, int y, int l, int r, int k){
int suml = dat[ls[y]]-dat[ls[x]];
int mid = (l+r)>>1;
if(dat[y]-dat[x]==0)return -1;
if(l==r)return l;
if(mid>k){
int rRes=askmi(ls[x],ls[y],l,mid,k);
if(rRes==-1)rRes=askmi(rs[x],rs[y],mid+1,r,k);
return rRes;
}
else return askmi(rs[x],rs[y],mid+1,r,k);
}
bool ck(int x, int l1, int r1, int l2, int r2){
int L = askmx(root[l1-1],root[r1-x+1],1,n,rk[l2]);
int R = askmi(root[l1-1],root[r1-x+1],1,n,rk[l2]);
if(L!=-1)L=rmq(L+1,rk[l2]);
if(R!=-1)R=rmq(rk[l2]+1,R);
return (L>=x||R>=x);
}
int main() {
tot=0;
scanf("%d %d", &n, &q);
scanf("%s",s+1);
m=122;n=strlen(s+1);
getSa();
getHeight();
init();
for(int i = 1; i <= n; i++){
root[i]=insert(root[i-1],1,n,rk[i],1);
}
init();
while(q--){
int l1,r1,l2,r2;
scanf("%d %d %d %d", &l1, &r1,&l2, &r2);
int ans = 0;
if(l2>=l1&&l2<=r1)ans=min(r2-l2+1,r1-l2+1);
int l = 0, r = min(r1-l1+1,r2-l2+1);
int res = 0;
while(l<=r){
int mid = (l+r)>>1;
if(ck(mid,l1,r1,l2,r2)){
l=mid+1;
res=mid;
}
else r=mid-1;
}
ans=max(ans,res);
printf("%d\n",ans);
}
return 0;
}
/*
8 1
ththhtht
1 6 7 8 85 292 31 259
79 299 5 232 8 10
aababbab
1 1 1 1
1 2 4 5
1 5 4 5
2 3 4 5
1 5 2 5
1 6 7 8
3 6 1 7
4 4 3 8
1 5 1 8
2 4 5 8
*/

法二:

既然\(lcp(i,j)\)对于i向左以及j向右都是单调不增的,我们可以二分出rk的左右边界L以及R,使得\(lcp(i,rk[l_2])\geq mid\)

然后我们对于(i,sa[i])建可持久化线段树,查询区间\((L+1,rk[l2])\)中是否有坐标在\([l_1,r_1-mid+1]\)中

这样复杂度是完美的\(O(nlog^2n)\)

代码:

我好懒,没写代码

BZOJ 4556(后缀数组+主席树求前驱后继+二分||后缀数组+二分+可持久化线段树)的更多相关文章

  1. Tsinsen A1505. 树(张闻涛) 倍增LCA,可持久化线段树,DFS序

    题目:http://www.tsinsen.com/A1505 A1505. 树(张闻涛) 时间限制:1.0s   内存限制:512.0MB    总提交次数:196   AC次数:65   平均分: ...

  2. BZOJ 2653 middle (可持久化线段树+中位数+线段树维护最大子序和)

    题意: 左端点在[a,b],右端点在[c,d],求这个线段里中位数(上取整)最大值 思路: 对数组离散化,对每一个值建中位数的可持久化线段树(有重复也没事),就是对于root[i],大于等于i的值为1 ...

  3. 【洛谷 P3834】 可持久化线段树1(主席树)

    题目链接 主席树=可持久化权值线段树. 如果你不会可持久化线段树,请右转 如果你不会权值线段树,请自行脑补,就是线段树维护值域里有多少个数出现. 可持久化线段树是支持查询历史版本的. 我们对每个数都进 ...

  4. 【bzoj2653】middle 可持久化线段树区间合并

    题目描述 一个长度为n的序列a,设其排过序之后为b,其中位数定义为b[n/2],其中a,b从0开始标号,除法取下整.给你一个长度为n的序列s.回答Q个这样的询问:s的左端点在[a,b]之间,右端点在[ ...

  5. [DP][SA][可持久化线段树]黑红兔

    源自 xyz32768 菜鸡的 FJ 省冬令营模拟赛题 原题 CF1063F Statement 给定一个长度为 \(n\) 的字符串 \(s\),仅包含小写英文字母 要从中从左往右选出若干段不相交的 ...

  6. 【BZOJ-3653】谈笑风生 DFS序 + 可持久化线段树

    3653: 谈笑风生 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 628  Solved: 245[Submit][Status][Discuss] ...

  7. [bzoj3207]花神的嘲讽计划Ⅰ[可持久化线段树,hash]

    将每k个数字求一个哈希值,存入可持久化线段树,直接查询即可 #include <iostream> #include <algorithm> #include <cstd ...

  8. 主席树||可持久化线段树+离散化 || 莫队+分块 ||BZOJ 3585: mex || Luogu P4137 Rmq Problem / mex

    题面:Rmq Problem / mex 题解: 先离散化,然后插一堆空白,大体就是如果(对于以a.data<b.data排序后的A)A[i-1].data+1!=A[i].data,则插一个空 ...

  9. luogu P3919 [模板]可持久化数组(可持久化线段树/平衡树)(主席树)

    luogu P3919 [模板]可持久化数组(可持久化线段树/平衡树) 题目 #include<iostream> #include<cstdlib> #include< ...

随机推荐

  1. RHEL6.6安装Oracle 11g RAC - 基于VMware的实验环境

    实验环境准备虚拟机:VMware® Workstation 14 Pro操作系统:Red Hat Enterprise Linux 6.6 x86_64rhel-server-6.6-x86_64-d ...

  2. Java set接口之HashSet集合原理讲解

    Set接口 java.util.set接口继承自Collection接口,它与Collection接口中的方法基本一致, 并没有对 Collection接口进行功能上的扩充,只是比collection ...

  3. WordPress使用PHPMailer发送gmail邮件

    wordpress使用phpmailer发送gmail邮件 0.保证用于gmail账号已经开启imap服务,且你能正常访问到gmail的smtp服务.(需要climb over the wall) 1 ...

  4. 洛谷 P5424 [USACO19OPEN]Snakes

    题目链接 题目描述 传说,数千年前圣帕特里克消灭了哞尔兰所有的蛇.然而,蛇们现在卷土重来了!圣帕特里克节是在每年的3月17日,所以Bessie要用彻底清除哞尔兰所有的蛇来纪念圣帕特里克. Bessie ...

  5. tomcat启动时检测到循环继承而栈溢出的问题:Caused by: java.lang.IllegalStateException: Unable to complete the scan for annotations for web application [/test] due to a StackOverflowError. Possible root causes include

    最近在公司更新一个老项目的时候,发现部署项目后tomcat报错,错误如下: Caused by: java.lang.IllegalStateException: Unable to complete ...

  6. 十大排序算法(Java实现)

    一.冒泡排序(Bubble Sort) public class BubbleSort { public static void main(String[] args) { int[] arr = { ...

  7. [bzoj1045] [洛谷P2512] [HAOI2008] 糖果传递

    Description 有n个小朋友坐成一圈,每人有ai个糖果.每人只能给左右两人传递糖果.每人每次传递一个糖果代价为1. Input 第一行一个正整数nn<=1'000'000,表示小朋友的个 ...

  8. 最强PostMan使用教程

    最近需要测试产品中的REST API,无意中发现了PostMan这个chrome插件,把玩了一下,发现postman秉承了一贯以来google工具强大,易用的特质.独乐乐不如众乐乐,特此共享出来给大伙 ...

  9. 把本地仓库同步到github上去

    1.愚蠢的没有进入之前设定的工作目录就开始用 git remote add origin https://github.com/bobowa/learngit.git 这个命令上传,报错如下 fata ...

  10. pip install 清华源加速

    经常要通过pip install安装需要的包,但是每当下载的文件比较大时,网速不够快,会导致报错.所以采用清华源来加速 清华大学开源软件镜像站 https://mirrors.tuna.tsinghu ...