码迷,mamicode.com
首页 > 其他好文 > 详细

loj6198 谢特

时间:2019-08-26 19:24:56      阅读:80      评论:0      收藏:0      [点我收藏+]

标签:ref   efi   etc   main   ble   class   end   插入   后缀   

题目

显然可以构造一棵后缀树,将问题转化成了在这棵树上找到两个点\(i,j\),使得\(w_i\bigoplus w_j+ len_{\rm LCA(i,j)}\)最大

于是在树上\(dfs\)的时候启发式合并\(\rm trie\)就好了,发现自己已经菜到不会写\(\rm trie\)了,\(\rm trie\)的插入做到最后一层还是有节点的,得先添加这个节点,之后才能返回

#include<bits/stdc++.h>
#define re register
#define LL long long
const int maxn=2e5+5;
inline int read() {
    char c=getchar();int x=0;while(c<'0'||c>'9') c=getchar();
    while(c>='0'&&c<='9') x=(x<<3)+(x<<1)+c-48,c=getchar();return x;
}
std::vector<int> v[maxn];
char S[maxn>>1];
int a[maxn>>1],tax[maxn>>1],A[maxn];
int ch[maxn*25][2];
int len[maxn],son[maxn][26],rt[maxn],fa[maxn];
int n,lst=1,cnt=1,tot,ans;
inline int max(int a,int b) {return a>b?a:b;}
inline int ins(int now,int w,int v) {
    if(!now) now=++tot;
    if(w==-1) return now;
    int u=(v>>w)&1;
    ch[now][u]=ins(ch[now][u],w-1,v);
    return now;
}
inline int chk(int now,int w,int v) {
    if(w==-1) return 0;
    int u=(v>>w)&1;
    if(ch[now][u^1]) return (1<<w)+chk(ch[now][u^1],w-1,v);
    return chk(ch[now][u],w-1,v);
}
inline int merge(int a,int b) {
    if(!a||!b) return a+b;
    ch[a][0]=merge(ch[a][0],ch[b][0]);
    ch[a][1]=merge(ch[a][1],ch[b][1]);
    return a;
}
inline void extend(int c,int w) {
    int p=++cnt,f=lst;lst=cnt;
    len[p]=len[f]+1,rt[p]=ins(rt[p],16,w);v[p].push_back(w);
    while(f&&!son[f][c]) son[f][c]=p,f=fa[f];
    if(!f) {fa[p]=1;return;}
    int x=son[f][c];
    if(len[f]+1==len[x]) {fa[p]=x;return;}
    int y=++cnt;
    len[y]=len[f]+1,fa[y]=fa[x],fa[x]=fa[p]=y;
    for(re int i=0;i<26;i++) son[y][i]=son[x][i];
    while(f&&son[f][c]==x) son[f][c]=y,f=fa[f];
}
int main() {
    n=read();scanf("%s",S+1);for(re int i=1;i<=n;i++) a[i]=read();
    for(re int i=n;i;--i) extend(S[i]-'a',a[i]);
    for(re int i=1;i<=cnt;i++) tax[len[i]]++;
    for(re int i=1;i<=n;i++) tax[i]+=tax[i-1];
    for(re int i=1;i<=cnt;i++) A[tax[len[i]]--]=i;
    for(re int i=cnt;i;--i) {
        int x=A[i];
        if(v[x].size()>v[fa[x]].size()) 
            std::swap(rt[x],rt[fa[x]]),std::swap(v[x],v[fa[x]]);
        int now=0;
        for(re int j=0;j<v[x].size();j++) {
            v[fa[x]].push_back(v[x][j]);
            now=max(now,chk(rt[fa[x]],16,v[x][j]));
        }
        rt[fa[x]]=merge(rt[fa[x]],rt[x]);
        ans=max(ans,now+len[fa[x]]);
    }
    std::cout<<ans;return 0;
}

loj6198 谢特

标签:ref   efi   etc   main   ble   class   end   插入   后缀   

原文地址:https://www.cnblogs.com/asuldb/p/11414328.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!