这道题市面上就两种法:一种是SA+二分+主席树,一种是SAM+二分+主席树(有不少人打线段树合并???)(除此之外还有一种利用炒鸡水的数据的暴力SA,贼快.....)(当时学SA的时候没做这道题,现在早忘了SA了)
  分析题意:就是对于一个字符串,每次询问一个子串在另一个子串里能匹配上的最大前缀(非严格前缀)长度.
  我们知道,处理前缀的工具并不是十分充足,后缀倒是有一大帮,所以说把字符串倒过来,而把字符串倒过来是SAM处理问题时的常用技巧.现在,我们直接找答案,仍然很难找到一种时间复杂度合法的做法,那么我们发现这个东西,是具有可二分的性质的,所以我们二分.这时,我们的问题转化为了"给出某个子串的right和len,快速求出其在某一区间内有无相同子串",然后利用SAM的节点的性质,我们又可以把问题转化为"给出某个子串的right和len,询问其所在节点的right集合是否存在元素在某一区间",到此,我们的问题已经很清晰了.
  对于找到这个子串所在的节点,我们可以找到其right所对应的前缀所在的节点(这个我们在构造的时候就可以处理出来),然后在parent树上倍增找到包含有长度为len的子串的节点,接下来就是看在其right集合中是否存在元素在某个区间内,这个时候我们就可以搞出parent树的dfs序,并对dfs序建立主席树,主席树的线段树区间维护的是right集合.
  好了我们得到了一种O(nlog^2n)的优秀做法!!!

#include <cstdio>
#include <cstring>
#include <algorithm>
char xB[(<<)+],*xS=xB,*xT=xB;
#define gtc (xS==xT&&(xT=(xS=xB)+fread(xB,1,1<<15,stdin),xS==xT)?0:*xS++)
inline void read(int &x){
register char ch=gtc;bool symbol=false;
for(x=;ch<''||ch>'';ch=gtc)if(ch=='-')symbol=true;
for(;ch>=''&&ch<='';x=(x<<)+(x<<)+ch-'',ch=gtc);
if(symbol)x=-x;
}
const int N=;
const int A=;
const int B=;
char s[N],tmp[N];
int pos[N];
int trans[N<<][A],max[N<<],link[N<<];
int last,rt,sz;
#define newnode(a) (max[++sz]=(a),sz)
int id[N<<],dfn[N<<],L[N<<],R[N<<];
int n,m;
struct V{
int to,next;
}c[N<<];
int head[N<<],t;
inline void add(int x,int y){
c[++t].to=y,c[t].next=head[x],head[x]=t;
}
int f[N<<][B];
int Ti;
struct Segment_Tree{
Segment_Tree *ch[];
int size;
inline void* operator new (size_t);
}*root[N<<],*C,*mempool,*null;
#define mid ((l+r)>>1)
inline void* Segment_Tree:: operator new(size_t){
if(C==mempool){
C=new Segment_Tree[(<<)+];
mempool=C+(<<)+;
}
return C++;
}
inline void Init(){
null=new Segment_Tree;
null->ch[]=null->ch[]=null;
null->size=;
root[]=null;
last=rt=newnode();
}
int w,q,nw,nq;
inline void insert(int x){
w=last,nw=newnode(max[w]+);
while(w&&trans[w][x]==)trans[w][x]=nw,w=link[w];
if(!w)link[nw]=rt;
else if(max[w]+==max[trans[w][x]])
link[nw]=trans[w][x];
else{
q=trans[w][x],nq=newnode(max[w]+);
memcpy(trans[nq],trans[q],sizeof(trans[nq]));
while(w&&trans[w][x]==q)trans[w][x]=nq,w=link[w];
link[nq]=link[q],link[q]=link[nw]=nq;
}
last=nw,id[nw]=max[nw],pos[max[nw]]=nw;
}
inline void insert(Segment_Tree *&p,Segment_Tree *lst,int l,int r,int aim){
p=new Segment_Tree(),*p=*lst;
++p->size;if(l==r)return;
if(aim<=mid)insert(p->ch[],lst->ch[],l,mid,aim);
else insert(p->ch[],lst->ch[],mid+,r,aim);
}
inline int query(Segment_Tree *a,Segment_Tree *b,int l,int r,int z,int y){
if(z<=l&&r<=y)return b->size-a->size;
int ret=;
if(z<=mid)ret+=query(a->ch[],b->ch[],l,mid,z,y);
if(mid<y)ret+=query(a->ch[],b->ch[],mid+,r,z,y);
return ret;
}
inline void dfs(int x){
L[x]=++Ti,dfn[Ti]=x;
for(int i=;i<B;++i)f[x][i]=f[f[x][i-]][i-];
for(int i=head[x];i;i=c[i].next)
f[c[i].to][]=x,dfs(c[i].to);
R[x]=Ti;
}
inline int get(int x,int len){
for(int i=B-;i>=;--i)
if(max[f[x][i]]>=len)
x=f[x][i];
return x;
}
inline bool check(int st,int len,int l,int r){
if(r-l+<len)return false;
int x=get(pos[st],len);
return query(root[L[x]-],root[R[x]],,n,l+len-,r);
}
int main(){
//freopen("rio.in","r",stdin);
Init(),scanf("%d%d%s",&n,&m,tmp+);
register int i;
for(i=;i<=n;++i)s[i]=tmp[n-i+];
for(i=;i<=n;++i)insert(s[i]-'a');
for(i=;i<=sz;++i)add(link[i],i);dfs();
for(i=;i<=sz;++i){
root[i]=root[i-];
if(id[dfn[i]])insert(root[i],root[i-],,n,id[dfn[i]]);
}
int a,b,x,y,l,r,ans;
while(m--){
read(b),read(a),read(y),read(x);
a=n-a+,b=n-b+,x=n-x+,y=n-y+;
r=y-x+,l=,ans=;
while(l<=r)
if(check(y,mid,a,b))ans=mid,l=mid+;
else r=mid-;
printf("%d\n",ans);
}
return ;
}

【BZOJ 4556】[Tjoi2016&Heoi2016]字符串 SAM+二分+主席树的更多相关文章

  1. bzoj 4556 [Tjoi2016&Heoi2016]字符串——后缀数组+主席树

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=4556 本来只要查 ht[ ] 数组上的前驱和后继就行,但有长度的限制.可以二分答案解决!然后 ...

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

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

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

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

  4. BZOJ 4556: [Tjoi2016&Heoi2016]字符串(后缀数组 + 二分答案 + 主席树 + ST表 or 后缀数组 + 暴力)

    题意 一个长为 \(n\) 的字符串 \(s\),和 \(m\) 个询问.每次询问有 \(4\) 个参数分别为 \(a,b,c,d\). 要你告诉它 \(s[a...b]\) 中的所有子串 和 \(s ...

  5. BZOJ 4556 [Tjoi2016&Heoi2016]字符串 ——后缀数组 ST表 主席树 二分答案

    Solution 1: 后缀数组暴力大法好 #include <map> #include <cmath> #include <queue> #include &l ...

  6. ●BZOJ 4556 [Tjoi2016&Heoi2016]字符串

    题链: http://www.lydsy.com/JudgeOnline/problem.php?id=4556 题解: 巨恶心...但是题很好呀,可以练习好几个比较麻烦的算法~ 1).预处理 首先用 ...

  7. bzoj 4552: [Tjoi2016&Heoi2016]排序【二分+线段树】

    二分值mid,然后把>=mid的赋值为1,其他赋值为0,每次排序就是算出区间内01的个数,然后分别把0和1放到连续的一段内,这些都可以用线段树来维护 二分的判断条件是操作完之后q位置上是否为1 ...

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

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

  9. [HEOI2016] 字符串 - 后缀数组,主席树,ST表,二分

    [HEOI2016] 字符串 Description 给定一个字符串 \(S\), 有 \(m\) 个询问,每个询问给定参数 \((a,b,c,d)\) ,求 \(s[a..b]\) 的子串与 \(s ...

随机推荐

  1. 阅读《大型网站技术架构》,并结合"重大需求征集系统"有感

    今天阅读了<大型网站技术架构:核心原理与案例分析>的第五.六.七章.这三张主要是讲述了一个系统的可用性.伸缩性和可扩展性.而根据文中所讲述的,一个系统的可用性主要是体现在这个系统的系统服务 ...

  2. 9.1 IIC驱动源码分析

    学习目标:分析linux内核源码下的i2c总线驱动 drivers/i2c/busses/i2c-s3c2410.c 和 driver/i2c/chips/eeprom.c 设备驱动: 一.i2c驱动 ...

  3. stata操作

    //stata操作 *************************数据基本操作****************************** gen varname = value //定义变量 r ...

  4. python读取大文件和普通文件

    读取文件,最常见的方式是: with open('filename', 'r', encoding = 'utf-8') as f: for line in f.readlines(): do_som ...

  5. Redis缓存数据库的安装与配置(1)

    1.安装 tarxf redis-3.2.5.tar.gz cd redis-3.2.5 make mkdir -p /usr/local/redis/bin src目录下这些文件作用如下 redis ...

  6. QOS-Qos标记和QOS-Policy策略

    QOS-Qos标记和qos  policy策略 2018年7月7日 20:29 主要标记方法 : IP ToS字段标记 IP Precedence(IP优先级) DSCP 二层 802.1p  CoS ...

  7. mac制作U盘启动器

    Infi-chu: http://www.cnblogs.com/Infi-chu/ 一.所需工具及必要条件: 1. 首先需要一个大于16GB U盘. 2.电脑系统版本应该大于10.11.X(因为之前 ...

  8. CSS3新特性回顾

    CSS3 介绍 开始实例 新特征简介 强大的CSS选择器 抛弃图片的视觉效果 盒模型变化(多列布局和弹性盒模型) 阴影效果 Web字体和web Font 图标 CSS33过渡与动画交互效果 媒体查询 ...

  9. SQL数据库 面试题

    一.sql理论题 1.触发器的作用? 答:触发器是一中特殊的存储过程,主要是通过事件来触发而被执行的.它可以强化约束,来维护数据的完整性和一致性,可以跟踪数据库内的操作从而不允许未经许可的更新和变化. ...

  10. shell重温---基础篇(printf命令&test命令)

    在shell中还有一个输出的命令,那就是printf了.它模仿的是C程序库(library)里的printf()程序,是由POSIX标准所定义,所以嘞,使用printf脚本比echo移植性要好一点,它 ...