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|
首先可以看出來,如果對於一個區間
①:如果
②:如果
③:如果
這樣如果從後往前掃左端點的話,那麼後面的區間就會被分成一塊一塊的,每一塊內的最優值都是一樣的,也就是說一個最優值影響的區間是連續的。(也就是當固定了左端點後右端點是單調的。)
每次新掃到一個左端點後,就可以看一下這個左端點影響到了後面哪一段區間。在影響的區間打上標記。
我剛開始本來想二分後面的區間,打標記的時候給線段樹區間染色,這樣是
可以維護一個棧,棧中的每一個元素對應了一段區間。每次掃到一個左端點後,依次彈出棧頂元素,知道當前這個左端點不會影響到當前棧頂的這個區間了。
還有種情況是可能會影響到最後那個區間的一部分,這樣需要在這個區間中二分一下這個區間從哪裂開。
時間複雜度是
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=100010;
char s[N];
struct Q{int x,y,No;}q[N];
struct S{int v,l,r,No;}stack[N];
int n,m,T,top,t1[N],t2[N],c[N],sa[N],rank[N],height[N],st[N][20],Log[N],ans[N];
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]);
}