zoukankan      html  css  js  c++  java
  • G. Death DBMS(查询每个主串和n个模板串匹配后val最大值,支持单点更新)

    题:https://codeforces.com/contest/1437/problem/G

    题意:首先给定n个模式串,每个模式串一开始价值为0,支持q个查询:

    • [1, x, val ]:将x位置的模式串价值改为val;
    • [2, s ] :找出在主串s中能匹配的模式串的最大值

    分析:

    • 将建立n个模式串的ac自动机,然后建立fail树;
    • 因为沿fail树向下走的感觉就是找更长的“后缀”,那么到最长后缀为止,所有可能后缀都在根节点到当前点上;
    • 所以询问就是(主串在trie上跑的每个节点映射到fail树上的)节点到fail树的根路径上的信息最大值;
    • 那么更新就是fail树上单点更新;
    • 那么要高效维护查询操作,就是对树进行树剖+线段树;
    • 因为可能会存在相同模式串,在trie上同时指向一个节点,所以要处理一下相同的情况
    #include<bits/stdc++.h>
    using namespace std;
    #define pb push_back
    #define lson root<<1,l,midd
    #define rson root<<1|1,midd+1,r
    const int M=3e5+5;
    int tr[M<<2];
    const int maxn=26;
    int trie[M][maxn],fail[M],las[M],sz[M],tp[M],son[M],id[M],dfn[M],rdfn[M],fa[M];
    char s[M];
    vector<int>g[M];
    multiset<int>mx[M];
    int tot;
    struct AC{
        int cnt=0;
        void Insert(char buf[],int sign){
            int len=strlen(buf),now=0;
            for(int i=0;i<len;i++){
                int x=buf[i]-'a';
                if(!trie[now][x])
                    trie[now][x]=++cnt;
                now=trie[now][x];
            }
            mx[now].insert(0);
            id[sign]=now;
        }
        void getfail(){
            queue<int>que;
            while(!que.empty()) que.pop();
            for(int i=0;i<maxn;i++)
                if(trie[0][i]){
                    fail[trie[0][i]]=0;
                    que.push(trie[0][i]);
                }
            while(!que.empty()){
                int now=que.front();
                que.pop();
                for(int i=0;i<maxn;i++)
                    if(trie[now][i]){
                        fail[trie[now][i]]=trie[fail[now]][i];
                        que.push(trie[now][i]);
                    }
                    else
                        trie[now][i]=trie[fail[now]][i];
            }
        }
    }ac;
    void dfs1(int u,int f){
        fa[u]=f,sz[u]=1;
        for(auto v:g[u]){
            if(v!=f){
                dfs1(v,u);
                sz[u]+=sz[v];
                if(!son[u]||sz[son[u]]<sz[v]) son[u]=v;
            }
    
        }
    }
    void dfs2(int u,int top){
        tp[u]=top;
        dfn[u]=++tot;
        rdfn[tot]=u;
        if(son[u])
            dfs2(son[u],top);
        for(auto v:g[u])
            if(v!=fa[u]&&v!=son[u])dfs2(v,v);
    }
    void up(int root){ tr[root]=max(tr[root<<1],tr[root<<1|1]); }
    void build(int root,int l,int r){
        tr[root]=-1;
        if(l==r){
            tr[root]=*mx[rdfn[l]].rbegin();
            return ;
        }
        int midd=(l+r)>>1;
        build(lson);
        build(rson);
        up(root);
    }
    void update(int pos,int c,int root,int l,int r){
        if(l==r){
            tr[root]=c;
            return ;
        }
        int midd=(l+r)>>1;
        if(pos<=midd)
            update(pos,c,lson);
        else
            update(pos,c,rson);
        up(root);
    }
    int query(int L,int R,int root,int l,int r){
        if(L<=l&&r<=R){
            return tr[root];
        }
        int midd=(l+r)>>1;
        int res=-1;
        if(L<=midd) res=query(L,R,lson);
        if(R>midd) res=max(res,query(L,R,rson));
        return res;
    }
    int trquery(int u){
        int res=-1;
        while(tp[u]!=0){
            res=max(res,query(dfn[tp[u]],dfn[u],1,1,tot));
            u=fa[tp[u]];
        }
        res=max(res,query(dfn[0],dfn[u],1,1,tot));
        return res;
    }
    int solve(char buf[]){
        int len=strlen(buf),now=0;
        int ans=-1;
        for(int i=0;i<len;i++){
            now=trie[now][buf[i]-'a'];
            ans=max(ans,trquery(now));
        }
        return ans;
    }
    int main(){
        int n,m;
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++){
            scanf("%s",s);
            ac.Insert(s,i);
        }
        ac.getfail();
        mx[0].insert(-1);
        for(int i=1;i<=ac.cnt;i++){
            g[fail[i]].pb(i);
            mx[i].insert(-1);
        }
        dfs1(0,-1);
        dfs2(0,0);
        build(1,1,tot);
        for(int i=1;i<=m;i++){
            int op;
            scanf("%d",&op);
            if(op==1){
                int x,val;
                scanf("%d%d",&x,&val);
                ///可能会出现相同的模式串,只要最大的那个
                ///更新时要记录上个更新值,用来下次更新时删除掉(也就是“覆盖”)
                mx[id[x]].erase(mx[id[x]].find(las[x]));
                las[x]=val;
                mx[id[x]].insert(las[x]);
                update(dfn[id[x]],*mx[id[x]].rbegin(),1,1,tot);
            }
            else{
                scanf("%s",s);
                printf("%d
    ",solve(s));
            }
        }
        return 0;
    }
    View Code
  • 相关阅读:
    网站后台编辑器怎样才能兼容IE6、IE8
    map area
    纯CSS圆角
    【转】Linux 查看某一进程的占用CPU的Cacti 脚本
    查看/修改Linux时区和时间,更新系统时间
    Centos下安装X Window+GNOME Desktop+FreeNX
    rhel6 kvm做桥接
    Gentoo网络配置
    常用正则表达式
    VS 设置备忘
  • 原文地址:https://www.cnblogs.com/starve/p/13899655.html
Copyright © 2011-2022 走看看