loj6198 谢特

题目

显然可以构造一棵后缀树,将问题转化成了在这棵树上找到两个点\(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;
}

转载于:https://www.cnblogs.com/asuldb/p/11414328.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值