题解 CF1437G 【Death DBMS】

· · 题解

CF1437G Death DBMS

一道比较模板的字符串题。

本来在考场上15minutes码完,但考试结束后两分钟才调完,没分了。

题意简述

给出n,m,然后给出n个字符串,每个字符串都有一个权值,最初权值都为0

然后有m个操作,操作有两种类型:

### 题解 很显然我们可以对$n$个模板串建立广义后缀自动机,然后对于每次询问,只用在$SAM$上匹配,每走一步查询一次当前点到跟的最小值。 显然这都可以用重链剖分+线段树维护,修改只用在线段树上修改即可。 复杂度$O(n\log^2 n)$。 **Hint:这道题有很多细节,需要好好想一下。** **Hint1:对于一些SAM上相同的串,我们需要找到他最上面的位置,同时将相同的串的权值标记在最上面的位置的multiset中。** **Hint2:对于到达一个SAM上的点$u$,若当前长度$=now[u]$,我们才从$u$查询,否则从$fa_u$查询。** **Hint3:在multiset中删值的时候只能删迭代器。** 晚上交的直接删的值,还过了,早上一起来赶紧把自己给hack了。 ### hack数据 hack by me - $\texttt{hack.in}
6 15
a
a
a
a
a
a
2 aaaa
1 4 5
2 aaa
1 2 5
1 6 5
2 a
2 aa
1 5 5
2 aa
2 a
1 4 1
2 aaa
1 5 1
1 6 2
2 a
0
5
5
5
5
5
5
5

这就是CF上的test90,顺带叉掉了8个人

参考代码

#pragma GCC optimize(4)
#include<bits/stdc++.h>
#define FOR(i,a,b) for(int i=a;i<=b;++i)
#define REP(u) for(int i=p[u];i!=-1;i=e[i].nxt)
#define ll long long
#define pb push_back
#define PII pair<int,int>
#define gc getchar()//(p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++)
using namespace std;
char buf[100000],*p1,*p2;
inline int gi()
{
    int x=0,f=1;
    char ch=gc;
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=gc;}
    while(ch>='0'&&ch<='9'){x=(x<<3)+(x<<1)+(ch^48);ch=gc;}
    return (f==1)?x:-x;
}
inline int max(int a,int b){return a<b?b:a;}
inline int min(int a,int b){return a<b?a:b;}
const int maxn=6e5+5;
int fa[maxn],len[maxn],tot=1,last=1,sz,p[maxn],son[maxn][26],pos[maxn],dfn[maxn],siz[maxn],tp[maxn],so[maxn],rel[maxn],val[maxn];
char s[maxn];
struct edge
{
    int v,nxt;
    edge(int vv=0,int nn=0){v=vv,nxt=nn;}
}e[maxn<<1];
inline void add(int u,int v)
{
    e[++sz]=edge(v,p[u]);
    p[u]=sz;
}
struct SAM
{
    inline void insert(int c)
    {
        int np=++tot,p=last;
        len[np]=len[p]+1,last=np;
        while(!son[p][c]&&p)son[p][c]=np,p=fa[p];
        if(!p)fa[np]=1;
        else
        {
            int q=son[p][c];
            if(len[q]==len[p]+1)fa[np]=q;
            else
            {
                int nq=++tot;
                len[nq]=len[p]+1;
                fa[nq]=fa[q];
                fa[q]=fa[np]=nq;
                memcpy(son[nq],son[q],sizeof(son[q]));
                while(p&&son[p][c]==q)son[p][c]=nq,p=fa[p];
            }
        }
    }
}sam;
int n,q;
inline void dfs(int u)
{
    if(len[u]==len[fa[u]]&&u!=1)rel[u]=rel[fa[u]];
    else rel[u]=u;
    siz[u]=1;
    REP(u)
    {
        int v=e[i].v;
        if(v==fa[u])continue;
        dfs(v);
        siz[u]+=siz[v];
        if(siz[v]>siz[so[u]])so[u]=v;
    }
}
inline void dfs2(int u,int topf)
{
    dfn[u]=++tot;
    tp[u]=topf;
    if(so[u])dfs2(so[u],topf);
    REP(u)
    {
        int v=e[i].v;
        if(v==fa[u]||v==so[u])continue;
        dfs2(v,v);
    }
}
struct segmentree
{
    #define ls u<<1
    #define rs u<<1|1
    static const int maxn=3e6+5;
    int maxv[maxn];
    inline void pushup(int u){maxv[u]=max(maxv[ls],maxv[rs]);}
    inline void update(int u,int l,int r,int x,int v)
    {
        if(l==r){return maxv[u]=v,void();}
        int mid=(l+r)>>1;
        if(x<=mid)update(ls,l,mid,x,v);
        else update(rs,mid+1,r,x,v);
        pushup(u);
    }
    inline int query(int u,int l,int r,int x,int y)
    {
        if(x<=l&&y>=r)return maxv[u];
        int ret=-1e9;
        int mid=(l+r)>>1;
        if(x<=mid)ret=query(ls,l,mid,x,y);
        if(y>mid)ret=max(ret,query(rs,mid+1,r,x,y));
        return ret;
    }
}tree;
inline int Query(int u)
{
    int ret=-1e9;
    while(u)
    {
        ret=max(ret,tree.query(1,1,n,dfn[tp[u]],dfn[u]));
        u=fa[tp[u]];
    }
    return ret;
}
multiset<int>ss[maxn];
int main()
{
    memset(p,-1,sizeof(p));
    n=gi(),q=gi();
    FOR(i,1,n)
    {
        last=1;
        scanf("%s",s+1);
        int len=strlen(s+1);
        FOR(j,1,len)sam.insert(s[j]-'a');
        pos[i]=last;
    }
    FOR(i,2,tot)add(fa[i],i);
    int xx=n;
    n=tot;
    tot=0;
    dfs(1);
    dfs2(1,1);
    FOR(i,2,tot)if(i!=rel[i])ss[rel[i]].insert(0);
    FOR(i,1,tot)tree.update(1,1,tot,i,-1e9);
    FOR(i,1,xx)tree.update(1,1,tot,dfn[rel[pos[i]]],0);
    while(q--)
    {
        int typ=gi();
        if(typ==2)
        {
            scanf("%s",s+1);
            int len1=strlen(s+1);
            int now=1,nowlen=0;
            int ans=-1;
            FOR(i,1,len1)
            {
                while(!son[now][s[i]-'a']&&now)now=fa[now],nowlen=len[now];
                if(now==0){now=1;nowlen=0;continue;}
                nowlen++;
                if(son[now][s[i]-'a'])now=son[now][s[i]-'a'];
                if(nowlen==len[now])ans=max(ans,Query(now));///fa[now]
                else ans=max(ans,Query(fa[now]));
            }
            printf("%d\n",ans);
        }
        else
        {
            int id=gi(),x=gi();
            if(pos[id]!=rel[pos[id]])
            {
                auto it=ss[rel[pos[id]]].find(val[pos[id]]);
                ss[rel[pos[id]]].erase(it);
                ss[rel[pos[id]]].insert(val[pos[id]]=x);
            }
            else val[pos[id]]=x;
            if(ss[rel[pos[id]]].size())
            {
                auto it=ss[rel[pos[id]]].end();
                it--;
                x=max(x,*it);
            }
            tree.update(1,1,n,dfn[rel[pos[id]]],max(x,val[rel[pos[id]]]));
        }
    }
    return 0;
}

希望本篇题解能给你带来收获。