Description
pps又开始dota视频直播了!一群每天被pps虐的蒟蒻决定学习pps的操作技术,他们把pps在这局放的技能记录了下来,每个技能用一个字符表示。经过研究,蒟蒻们发现字典序更大的连招威力更大。于是所有蒟蒻都想学习pps最强的连招。但是他们太弱了,不能学会整个视频里的连招,只能学会陈老师一段区间间内的连招,可是这个他们求不出,于是只好向你求助。为了蒟蒻们不再被pps虐(怎么可能),请你帮帮他们。简化题意:给你一个字符串,每次询问你一段区间的字典序最大的子串。
Solution
前几天WC的讲义上有讲这个题目……
离线,把询问按照
r
r
r从小到大排序。对于同一个
r
r
r,随着
l
l
l的右移,答案显然也是单调右移的,我们可以维护所有可能成为答案的位置,然后询问
l
o
w
e
r
_
b
o
u
n
d
lower\_bound
lower_bound即可。考虑怎么维护这个东西,对于两个后缀
s
[
i
.
.
n
]
、
s
[
j
.
.
n
]
(
i
<
j
)
s[i..n]、s[j..n](i<j)
s[i..n]、s[j..n](i<j),若他们的
L
C
P
LCP
LCP长度为
l
e
n
len
len,且
s
[
j
+
l
e
n
]
>
s
[
i
+
l
e
n
]
s[j+len]>s[i+len]
s[j+len]>s[i+len],那么在
r
<
j
+
l
e
n
r<j+len
r<j+len的时候,是
s
[
i
.
.
n
]
s[i..n]
s[i..n]更优,而
r
≥
j
+
l
e
n
r\ge j+len
r≥j+len时,则是
s
[
j
.
.
n
]
s[j..n]
s[j..n]更优,因为我们是从左到右扫
r
r
r,所以我们要在扫到
j
+
l
e
n
j+len
j+len的时候删掉
s
[
i
.
.
n
]
s[i..n]
s[i..n]这个后缀,所以用一个set维护这个单调栈。注意一个后缀被删后,比他更差的后缀也要同时被删除。
Code
#include<bits/stdc++.h>
using namespace std;
#define LL long long
#define pa pair<int,int>
const int Maxn=100010;
const int inf=2147483647;
const unsigned int base=233;
int read()
{
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9')x=(x<<3)+(x<<1)+(ch^48),ch=getchar();
return x*f;
}
int n,m,sta[Maxn],top=0,ans[Maxn];bool mark[Maxn];
char s[Maxn];
unsigned int h[Maxn],Pow[Maxn];
unsigned int g(int l,int r){return h[l]-h[r+1]*Pow[r-l+1];}
int lcp(int a,int b)
{
int l=1,r=n-max(a,b)+1;
while(l<=r)
{
int mid=l+r>>1;
if(g(a,a+mid-1)==g(b,b+mid-1))l=mid+1;
else r=mid-1;
}
return l-1;
}
set<int>S;
vector<int>p[Maxn],del[Maxn];
vector<pa>query[Maxn];
bool dfs(int x)
{
mark[x]=true;S.erase(x);
for(int i=0;i<p[x].size();i++)
if(!mark[p[x][i]])dfs(p[x][i]);
}
int main()
{
scanf("%s",s+1);n=strlen(s+1);
h[n+1]=0;for(int i=n;i;i--)h[i]=h[i+1]*base+s[i];
Pow[0]=1;for(int i=1;i<=n;i++)Pow[i]=Pow[i-1]*base;
m=read();
for(int i=1;i<=m;i++)
{
int l=read(),r=read();
query[r].push_back(make_pair(l,i));
}
for(int r=1;r<=n;r++)
{
S.insert(r);
while(top)
{
int t=lcp(r,sta[top]);
if(s[r+t]<s[sta[top]+t])break;
p[r].push_back(sta[top]);del[r+t].push_back(sta[top]);top--;
}
sta[++top]=r;
for(int i=0;i<del[r].size();i++)
if(!mark[del[r][i]])dfs(del[r][i]);
for(int i=0;i<query[r].size();i++)
{
pa t=query[r][i];
ans[t.second]=*S.lower_bound(t.first);
}
}
for(int i=1;i<=m;i++)printf("%d\n",ans[i]);
}