peiwenjun's blog 没有知识的荒原

CF1437G Death DBMS 题解

题目描述

给定 \(n\) 个字符串 \(s_i\) ,每个字符串有一个权值,初始为 \(0\)

接下来 \(m\) 次操作:

  • 将第 \(k\) 个字符串的权值修改为 \(x\)
  • 给定一个字符串 \(t\) ,求所有是 \(t\) 的子串的字符串 \(s_i\) 权值最大值,如果不存在则输出 -1

数据范围

  • \(1\le n,m\le 3\cdot 10^5\)
  • \(0\le x\le 10^9,1\le \sum|s|,\sum|t|\le3\cdot10^5\)

分析

重工业数据结构,想题五分钟,写题两小时。

子串相关,果断建出 \(\texttt{AC}\) 自动机。

对于第一类操作,注意可能有重复的字符串,用 multiset 维护 \(\texttt{AC}\) 自动机上每个点的权值。

对于第二类操作,把 \(t\) 放在 \(\texttt{AC}\) 自动机上跑。每走一个字符,查询 \(fail\) 树上当前位置在 \(fail\) 树上到根的链中权值最大值,树剖线段树即可。

时间复杂度 \(\mathcal O((n+m+\sum|s|+\sum|t|)\log^2|s|)\)

天坑:常规写法中 \(fail\) 树下标从 \(0\) 开始,失配时会走到 \(0\) 号点(根节点),但是常规写法树剖初始化 son[u]=0 以便后续更新。因此本题在求 son[u] 时需要特判 son[u]=0 的情形。如果你想下标平移也不是不行,但是会多很多细节并且像博主一样浪费好多时间

#include<bits/stdc++.h>
using namespace std;
const int maxn=3e5+5;
int m,n,cnt,tot;
int pos[maxn],val[maxn];
char s[maxn];
int fa[maxn],sz[maxn],son[maxn],dfn[maxn],top[maxn];
vector<int> g[maxn];
struct node
{
    int ch[26],fail;
    multiset<int> s;
}f[maxn];
void getfail()
{
    queue<int> q;
    for(int i=0;i<26;i++) if(f[0].ch[i]) q.push(f[0].ch[i]);
    while(!q.empty())
    {
        int u=q.front();q.pop();
        for(int i=0;i<26;i++)
            if(f[u].ch[i]) f[f[u].ch[i]].fail=f[f[u].fail].ch[i],q.push(f[u].ch[i]);
            else f[u].ch[i]=f[f[u].fail].ch[i];
    }
}
void dfs1(int u)
{
    sz[u]=1;
    for(auto v:g[u])
    {
        fa[v]=u,dfs1(v),sz[u]+=sz[v];
        if(!son[u]||sz[v]>sz[son[u]]) son[u]=v;
    }
}
void dfs2(int u,int _f)
{
    dfn[u]=++cnt,top[u]=_f;
    if(son[u]) dfs2(son[u],_f);
    for(auto v:g[u]) if(v!=son[u]) dfs2(v,v);
}
namespace sgmt
{
    int p,mx[3*maxn];
    void pushup(int p)
    {
        mx[p]=max(mx[p<<1],mx[p<<1|1]);
    }
    void init()
    {
        p=1<<(__lg(cnt)+1);
        for(int i=p;i<=p+cnt+1;i++) mx[i]=-1;
        for(int i=1;i<=n;i++) mx[p+dfn[pos[i]]]=0;
        for(int i=p-1;i>=1;i--) pushup(i);
    }
    void modify(int x,int v)
    {
        x+=p,mx[x]=v;
        for(;x!=1;x>>=1) pushup(x>>1);
    }
    int query(int l,int r)
    {
        int res=-1;
        for(l=p+l-1,r=p+r+1;l^r^1;l>>=1,r>>=1)
        {
            if(~l&1) res=max(res,mx[l^1]);
            if(r&1) res=max(res,mx[r^1]);
        }
        return res;
    }
}
int query(int x)
{
    int res=-1;
    while(x) res=max(res,sgmt::query(dfn[top[x]],dfn[x])),x=fa[top[x]];
    return res;
}
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1,p=0;i<=n;i++)
    {
        scanf("%s",s+1),p=0;
        for(int j=1,l=strlen(s+1);j<=l;j++)
        {
            int c=s[j]-'a';
            if(!f[p].ch[c]) f[p].ch[c]=++tot;
            p=f[p].ch[c];
        }
        pos[i]=p,f[p].s.insert(0);
    }
    getfail();
    for(int i=1;i<=tot;i++) g[f[i].fail].push_back(i);
    dfs1(0),dfs2(0,0),sgmt::init();
    for(int op=0,x=0,y=0;m--;)
    {
        scanf("%d",&op);
        if(op==1)
        {
            scanf("%d%d",&x,&y);
            auto &s=f[pos[x]].s;
            s.erase(s.find(val[x])),s.insert(val[x]=y);
            sgmt::modify(dfn[pos[x]],*--s.end());
        }
        else
        {
            scanf("%s",s+1),x=-1;
            for(int i=1,l=strlen(s+1),p=0;i<=l;i++) p=f[p].ch[s[i]-'a'],x=max(x,query(p));
            printf("%d\n",x);
        }
    }
    return 0;
}

posted on 2022-05-04 20:18  peiwenjun  阅读(8)  评论(0)    收藏  举报

导航