您的位置:首页 > 其它

【NOI2017模拟3.25】历史行程

2017-03-29 20:55 375 查看

Description

给出一个长度为n的字符串,m次询问前缀l~r中两两的最长后缀最长是多少。

n,m<=1e5

Solution

显然先倒过来,询问变成求后缀的lcp

SA处理一下就好了。

但是rank不是有序的,无法处理,怎么办呢?

可以离线莫队,维护一个set,每次插入或删除都可以log n解决。

但是复杂度过高会T怎么办呢?

我们每次插入就是要求某个点的前继和后继。

这个东西可以用双向链表来维护。

但是链表如何O(1)插入?

我们会发现,如果我们按照之前删除的倒序插入,那么插入的复杂度就是O(1)的。

于是我们处理出询问左端点所在块的左端点到询问右端点的链表。

这个可以通过把右端点从大到小排序来实现。

因为左端点就是在块内变化的,所以每次我们把左端点删到这个块的右端点,然后再加回去,这样链表是不会发生变化的。

于是我们就强行把维护前后继的log给去掉了=w=

具体实现看代码应该能懂吧。。。

Code

#include <cmath>
#include <cstdio>
#include <cstring>
#include <algorithm>
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define fd(i,a,b) for(int i=a;i>=b;i--)
using namespace std;
const int N=1e5+5,M=400;
int sa[N],rank[N],height[N],w[N],x[N],y[N],mi[18],f[N][18],lg
;
int n,m,l,r,tot,L
,R
,a
,b
,pre
,suf
,an
,ans;
char st
;
struct note{
int l,r,id;
friend bool operator < (note x,note y) {
return b[x.l]<b[y.l]||b[x.l]==b[y.l]&&x.r>y.r;
}
}ask
;
void tsort() {
memset(w,0,sizeof(w));int mx=0;
fo(i,1,n) w[x[y[i]]]++,mx=max(mx,x[y[i]]);
fo(i,1,mx) w[i]+=w[i-1];
fd(i,n,1) sa[w[x[y[i]]]--]=y[i];
}
void get_sa() {
fo(i,1,n) y[i]=i;tsort();
for(int j=1;j<=n;j=j*2) {
int k=0;fo(i,n-j+1,n) y[++k]=i;
fo(i,1,n) if (sa[i]>j) y[++k]=sa[i]-j;
tsort();
fo(i,1,n) y[i]=x[i],x[i]=0;
x[sa[1]]=k=1;
fo(i,2,n) {
if (y[sa[i]]!=y[sa[i-1]]||y[sa[i]+j]!=y[sa[i-1]+j]) k++;
x[sa[i]]=k;
}
}
fo(i,1,n) rank[sa[i]]=i;
}
void get_height() {
int k=0;
fo(i,1,n) {
if (k) k--;
int j=sa[rank[i]-1];
while (j+k<=n&&i+k<=n&&st[j+k]==st[i+k]) k++;
height[rank[i]]=k;
}
}
void get_rmq() {
mi[0]=1;int len=log(n)/log(2);
fo(i,1,len) mi[i]=mi[i-1]*2;
fo(i,1,n) f[i][0]=height[i],lg[i]=log(i)/log(2);
fo(j,1,len)
fo(i,1,n-mi[j]+1)
f[i][j]=min(f[i][j-1],f[i+mi[j-1]][j-1]);
}
int lcp(int x,int y) {
if (x<1||y>n||x==y) return 0;
x++;int z=lg[y-x+1];
return min(f[x][z],f[y-mi[z]+1][z]);
}
void prepare() {
fo(i,1,n) suf[i]=i+1,pre[i]=i-1;
suf[0]=1;pre[n+1]=n;
}
void ins(int x) {
ans=max(ans,max(lcp(pre[x],x),lcp(x,suf[x])));
suf[pre[x]]=x;pre[suf[x]]=x;
}
void del(int x) {
pre[suf[x]]=pre[x];
suf[pre[x]]=suf[x];
}
int main() {
freopen("history.in","r",stdin);
freopen("history.out","w",stdout);
scanf("%d%d",&n,&m);
scanf("%s",st+1);
fo(i,1,n/2) swap(st[i],st[n-i+1]);
fo(i,1,n) x[i]=st[i];
get_sa();
get_height();
get_rmq();
fo(i,1,n) b[i]=(i-1)/M+1;
fo(i,1,m) {
scanf("%d%d",&l,&r);
swap(l,r);l=n-l+1,r=n-r+1;
if (b[l]==b[r]) {
fo(j,l,r) a[j-l+1]=rank[j];
sort(a+1,a+r-l+1+1);
ans=0;
fo(j,2,r-l+1) ans=max(ans,lcp(a[j-1],a[j]));
an[i]=ans;
continue;
}
ask[++tot].id=i;
ask[tot].l=l;ask[tot].r=r;
}
sort(ask+1,ask+tot+1);
int cnt=(n-1)/M+((n-1)%M>0);
fo(i,1,cnt) L[i]=R[i-1]+1,R[i]=min(L[i]+M-1,n);
prepare();L[cnt+1]=n+1;
int l=1,r=n;
fo(i,1,tot) {
if (b[ask[i].l]!=b[ask[i-1].l]) {
prepare();r=n;
while (L[l+1]<=ask[i].l) l++;
fo(j,1,R[l]-1) del(rank[j]);
fd(j,n,R[l]+1) del(rank[j]);
ans=0;
fo(j,R[l]+1,n) ins(rank[j]),a[j]=ans;
fd(j,R[l]-1,L[l]) ins(rank[j]);
}
while (r>ask[i].r) del(rank[r]),r--;
ans=a[r];
fo(j,L[l],R[l]-1) del(rank[j]);
fd(j,R[l]-1,ask[i].l) ins(rank[j]);
an[ask[i].id]=ans;
fd(j,ask[i].l-1,L[l]) ins(rank[j]);
}
fo(i,1,m) printf("%d\n",an[i]);
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: