传送门
题解:
写完去看了一下正解,是后缀数组上按照height从大到小对01Trie启发式合并。
然而建出后缀树直接把01Trie拿来dsu on tree岂不妙哉?
没什么好说的,挺普通的一道题。
代码:
#include<bits/stdc++.h>
#define ll long long
#define re register
#define gc get_char
#define cs const
namespace IO{
inline char get_char(){
static cs int Rlen=1<<22|1;
static char buf[Rlen],*p1,*p2;
return (p1==p2)&&(p2=(p1=buf)+fread(buf,1,Rlen,stdin),p1==p2)?EOF:*p1++;
}
inline int get_s(char *s){
int len=0;char c;
while(isspace(c=gc()));
while(s[len++]=c,!isspace(c=gc())&&c!=EOF);
s[len]='\0';return len;
}
template<typename T>
inline T get(){
char c;
while(!isdigit(c=gc()));T num=c^48;
while(isdigit(c=gc()))num=(num+(num<<2)<<1)+(c^48);
return num;
}
inline int getint(){return get<int>();}
}
using namespace IO;
using std::cerr;
using std::cout;
cs int N=1e5+5;
int n;
char s[N];
int w[N];
int ans;
namespace Trie{
cs int N=::N*20,B=17;
int son[N][2],tot;
inline void clear(){
while(tot){
son[tot][0]=son[tot][1]=0;
--tot;
}
son[0][0]=son[0][1]=0;
}
inline void ins(int val){
int cur=0;
for(int re i=B-1;~i;--i){
bool f=val&(1<<i);
if(!son[cur][f])son[cur][f]=++tot;
cur=son[cur][f];
}
}
inline int query(int val){
if(!tot)return -1e9;
int cur=0,res=0;
for(int re i=B-1;~i;--i){
bool f=val&(1<<i);
if(son[cur][!f])res|=1<<i,cur=son[cur][!f];
else cur=son[cur][f];
}
return res;
}
}
namespace SAM{
static cs int N=::N<<1;
int son[N][26],len[N],fa[N],last=1,now=1;
int val[N];
inline void push_back(char c,int w){
c-='a';
int p=last,cur=last=++now;
len[cur]=len[p]+1;val[cur]=w;
for(;p&&!son[p][c];p=fa[p])son[p][c]=cur;
if(!p)fa[cur]=1;
else if(len[son[p][c]]==len[p]+1)fa[cur]=son[p][c];
else {
int nq=++now,q=son[p][c];
val[nq]=-1;
memcpy(son[nq],son[q],sizeof son[q]);
len[nq]=len[p]+1;fa[nq]=fa[q];
fa[q]=fa[cur]=nq;
for(;p&&son[p][c]==q;p=fa[p])son[p][c]=nq;
}
}
std::vector<int> E[N];
int in[N],out[N],p[N],clk;
int siz[N],ch[N];
inline void build(){
for(int re i=n;i;--i)push_back(s[i],w[i]);
for(int re i=2;i<=now;++i)E[fa[i]].push_back(i);
}
void dfs(int u){
siz[u]=val[u]!=-1;
p[in[u]=++clk]=u;
for(int re v:E[u]){
dfs(v);
siz[u]+=siz[v];
if(siz[v]>siz[ch[u]])ch[u]=v;
}
out[u]=clk;
}
void dsu(int u){
for(int re v:E[u])if(v!=ch[u])dsu(v),Trie::clear();
if(ch[u])dsu(ch[u]);
for(int re v:E[u])if(v!=ch[u]){
for(int re i=in[v];i<=out[v];++i)if(~val[p[i]])
ans=std::max(ans,len[u]+Trie::query(val[p[i]]));
for(int re i=in[v];i<=out[v];++i)if(~val[p[i]])
Trie::ins(val[p[i]]);
}
if(~val[u]){
ans=std::max(ans,len[u]+Trie::query(val[u]));
Trie::ins(val[u]);
}
}
}
signed main(){
// freopen("shit.in","r",stdin);
n=getint();
get_s(s+1);
for(int re i=1;i<=n;++i)w[i]=getint();
SAM::build();
SAM::dfs(1);
SAM::dsu(1);
cout<<ans<<"\n";
return 0;
}