您的位置:首页 > 其它

[bzoj4453]cys就是要拿英魂!

2016-04-19 09:19 239 查看

4453: cys就是要拿英魂!

Time Limit: 3 Sec Memory Limit: 128 MB

Submit: 66 Solved: 33

[Submit][Status][Discuss]

Description

pps又开始dota视频直播了!

一群每天被pps虐的蒟蒻决定学习pps的操作技术,他们把pps在这局放的技能记录了下来,每个技能用一个字符表示。经过研究,蒟蒻们发现字典序更大的连招威力更大。于是所有蒟蒻都想学习pps最强的连招。但是他们太弱了,不能学会整个视频里的连招,只能学会陈老师一段区间间内的连招,可是这个他们求不出,于是只好向你求助。为了蒟蒻们不再被pps虐(怎么可能),请你帮帮他们。

简化题意:

给你一个字符串,每次询问你一段区间的字典序最大的子串。

Input

第一行是一个字符串S,表示pps放的技能

第二行一个正整数Q,表示询问个数

接下来Q行,每行两个正整数[l,r],表示询问区间[l,r]中的字典序最大的子串。

Output

Q行,每行一个正整数,表示该区间内字典序最大的子串的起始位置。

Sample Input

Lets_go_mod_p!

5

2 2

3 3

2 5

1 10

2 9


Sample Output

2

3

3

3

3


数据范围:

1<=|S|<=100000

1<=Q<=100000

1<=l<=r<=|S|


首先可以看出来,如果对于一个区间[l,r]有两个后缀i,j他们呢个更优可以分这么几种情况来讨论(假设i<j):

①:如果rank[i]>rank[j],那么i肯定比j优。

②:如果rank[i]<rank[j]&&lcp(i,j)<r−j+1,那么j肯定比i优。

③:如果rank[i]<rank[j]&&lcp(i,j)>=r−j+1,那么i比j更优。

这样如果从后往前扫左端点的话,那么后面的区间就会被分成一块一块的,每一块内的最优值都是一样的,也就是说一个最优值影响的区间是连续的。(也就是当固定了左端点后右端点是单调的。)

每次新扫到一个左端点后,就可以看一下这个左端点影响到了后面哪一段区间。在影响的区间打上标记。

我刚开始本来想二分后面的区间,打标记的时候给线段树区间染色,这样是O(nlog2n)的。

可以维护一个栈,栈中的每一个元素对应了一段区间。每次扫到一个左端点后,依次弹出栈顶元素,知道当前这个左端点不会影响到当前栈顶的这个区间了。

还有种情况是可能会影响到最后那个区间的一部分,这样需要在这个区间中二分一下这个区间从哪裂开。

时间复杂度是O(nlogn)的。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=100010;
char s
;
struct Q{int x,y,No;}q
;
struct S{int v,l,r,No;}stack
;
int n,m,T,top,t1
,t2
,c
,sa
,rank
,height
,st
[20],Log
,ans
;
inline int in(){
int x=0;char ch=getchar();
while(ch<'0'||ch>'9') ch=getchar();
while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
return x;
}
inline bool cmp(int *y,int p,int q,int k){
int o0,o1;
o0=p+k>=n?-1:y[p+k];
o1=q+k>=n?-1:y[q+k];
return o0==o1&&y[p]==y[q];
}
inline void build_sa(){
int i,k,p,*x=t1,*y=t2;
for(i=0;i<m;++i) c[i]=0;
for(i=0;i<n;++i) ++c[x[i]=s[i]];
for(i=1;i<m;++i) c[i]+=c[i-1];
for(i=n-1;~i;--i) sa[--c[x[i]]]=i;
for(k=1;k<=n;k<<=1){
for(p=0,i=n-k;i<n;++i) y[p++]=i;
for(i=0;i<n;++i) if(sa[i]>=k) y[p++]=sa[i]-k;
for(i=0;i<m;++i) c[i]=0;
for(i=0;i<n;++i) ++c[x[y[i]]];
for(i=1;i<m;++i) c[i]+=c[i-1];
for(i=n-1;~i;--i) sa[--c[x[y[i]]]]=y[i];
swap(x,y);
x[sa[0]]=0;m=1;
for(i=1;i<n;++i) x[sa[i]]=cmp(y,sa[i],sa[i-1],k)?m-1:m++;
if(m>=n) break;
}
}
inline void build_height(){
int i,k=0,j;
for(i=0;i<n;++i) rank[sa[i]]=i;
for(i=0;i<n;++i){
if(!rank[i]) continue;
k=k?--k:k;
j=sa[rank[i]-1];
while(s[j+k]==s[i+k]) ++k;
height[rank[i]]=k;
}
memset(st,127/3,sizeof(st));
for(i=0;i<n;++i) st[i][0]=height[i];
for(j=1;j<=20;++j)
for(i=0;i+(1<<(j-1))<n;++i)
st[i][j]=min(st[i][j-1],st[i+(1<<(j-1))][j-1]);
for(j=0,i=1;i<=n;++i){
if((1<<(j+1))<=i) ++j;
Log[i]=j;
}
}
inline int LCP(int x,int y){
if(x>y) swap(x,y);
int k=Log[y-x];++x;
return min(st[x][k],st[y-(1<<k)+1][k]);
}
inline bool CMP(Q x,Q y){return x.x>y.x;}
#define mid (l+r)/2
inline bool check(int x,int y,int z){
if(rank[x]>rank[y]) return true;
int len=LCP(rank[x],rank[y]);
if(len<z-y+1) return false;
return true;
}
int main(){
int i,j;
scanf("%s",s);
n=strlen(s);
for(i=0;i<n;++i) m=max(m,(int)s[i]);
++m;build_sa();
build_height();
T=in();
for(i=1;i<=T;++i) q[i].x=in()-1,q[i].y=in()-1,q[i].No=i;
sort(q+1,q+T+1,CMP);
stack[0].l=n;stack[top=1].v=rank[n-1];
stack[top].No=stack[top].l=stack[top].r=n-1;
for(j=1;q[j].x==n-1;++j) ans[q[j].No]=n;
for(i=n-2;~i&&j<=T;--i){
int now=top,l,r,flag=0;
for(;top;--top){
l=check(i,stack[top].No,stack[top].l);
r=check(i,stack[top].No,stack[top].r);
if(l&&r) continue;
if(!l&&!r) break;
if(l&&!r){
flag=1;
break;
}
}
if(flag){
now=l=stack[top].l;r=stack[top].r;
while(l<r){
if(check(i,stack[top].No,mid)) now=max(now,mid),l=mid+1;
else r=mid;
}
stack[top].l=now+1;
stack[++top].v=rank[i];
stack[top].r=now;
stack[top].l=stack[top].No=i;
}
else{
stack[++top].v=rank[i];
stack[top].No=stack[top].l=i;
stack[top].r=stack[top-1].l-1;
}
while(q[j].x==i&&j<=T){
l=1;r=top;now=q[j].y;
while(l<r){
if(now>=stack[mid].l&&now<=stack[mid].r) break;
if(now<stack[mid].l) l=mid+1;
else r=mid;
}
ans[q[j].No]=stack[mid].No+1;
++j;
}
}
for(i=1;i<=T;++i) printf("%d\n",ans[i]);
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: