题意
给了一个字符串,字符串每个位置有一个权值 .定义字符串的两个后缀 的价值为 xor
求最大价值
解法
首先分开考虑:对于
,可以先求出sa,和height,然后是[i,j]的区间min.
对于
xor
.,可以用01trie求.
然后把两个价值统一起来的方法就是把height从大到小排序,保证每个加进去的都是最小的一个,然后还需要用并查集维护现在一个区间有哪些位置,然后就用trie在这些数里选出最大值就可以了.并查集合并的时候需要启发式合并.
注意:我现在对sa的记忆和理解有写模糊了.需要在这里备忘一下:
sa[]:排名为i的后缀是哪个
rk[]:第i个后缀的排名
h[]:排名为i的后缀和排名为i-1的后缀的lcp
#include<bits/stdc++.h>
using namespace std;
const int maxn=5e5+5;
const int mx=20;
inline int read(){
char c=getchar();int t=0,f=1;
while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}
while(isdigit(c)){t=(t<<3)+(t<<1)+(c^48);c=getchar();}
return t*f;
}
int n,w[maxn],x[maxn],y[maxn],sa[maxn],rk[maxn],h[maxn],t[maxn],m=300,c[maxn*mx][2];
char s[maxn];
void get(){
for(int i=1;i<=n;i++)t[x[i]=s[i]]++;
for(int i=1;i<=m;i++)t[i]+=t[i-1];
for(int i=n;i>=1;i--)sa[t[x[i]]--]=i;
for(int k=1;k<=n;k<<=1){
int num=0;
for(int i=n-k+1;i<=n;i++)y[++num]=i;
for(int i=1;i<=n;i++)if(sa[i]>k)y[++num]=sa[i]-k;
memset(t,0,sizeof(t));
for(int i=1;i<=n;i++)t[x[i]]++;
for(int i=1;i<=m;i++)t[i]+=t[i-1];
for(int i=n;i>=1;i--){sa[t[x[y[i]]]--]=y[i];y[i]=0;}
swap(x,y);
x[sa[1]]=1;num=1;
for(int i=2;i<=n;i++)
x[sa[i]]=(y[sa[i]]==y[sa[i-1]])&&(y[sa[i]+k]==y[sa[i-1]+k])?num:++num;
if(num==n)break;
m=num;
}
for(int i=1;i<=n;i++)rk[sa[i]]=i;
int k=0;
for(int i=1;i<=n;i++){//求height,枚举i而不是rk[i]
if(k)k--;int j=sa[rk[i]-1];
while(s[i+k]==s[j+k]&&i+k<=n&&j+k<=n)k++;
h[rk[i]]=k;
}
}
int sz[maxn],f[maxn],rt[maxn],cnt;
inline int find(int x){
return f[x]==x?f[x]:f[x]=find(f[x]);
}
int build(int x){
int rt=++cnt,now=rt;
for(int i=mx;i>=0;i--){
c[now][(x>>i)&1]=++cnt,now=cnt;
}
return rt;
}
typedef pair<int,int> pii;
pii so[maxn];
int query(int x,int y,int z=0){
int best=z;
if(c[x][0]){
if(c[y][1])best=query(c[x][0],c[y][1],2*z+1);
else best=query(c[x][0],c[y][0],2*z);
}
if(c[x][1]){
if(c[y][0])best=max(best,query(c[x][1],c[y][0],2*z+1));
else best=max(best,query(c[x][1],c[y][1],2*z));
}
return best;
}
int ans;
void merge(int x,int y){//trie树合并类似线段树合并,这里不需要新建节点是因为没有修改.
if(c[x][0]){
if(c[y][0])merge(c[x][0],c[y][0]);
else c[y][0]=c[x][0];
}
if(c[x][1]){
if(c[y][1])merge(c[x][1],c[y][1]);
else c[y][1]=c[x][1];
}
}
int main(){
n=read();
scanf("%s",s+1);
for(int i=1;i<=n;i++)w[i]=read();
get();
for(int i=1;i<=n;i++){
sz[i]=1,f[i]=i;rt[i]=build(w[sa[i]]);
}
for(int i=2;i<=n;i++){
so[i-1]=pii(n-h[i],i);
}
sort(so+1,so+n);
int ret=0;
for(int i=1;i<n;i++){
int x=so[i].second,y=x-1,z=n-so[i].first;
x=find(x),y=find(y);
if(sz[x]<sz[y])swap(x,y);
int tmp=query(rt[y],rt[x])+z;
if(tmp>ans)ans=tmp;
sz[x]+=sz[y];
merge(rt[y],rt[x]);
f[y]=x;
}
printf("%d\n",ans);
return 0;
}