• Codeforces 1437G Death DBMS AC自动机


    Codeforces 1437G Death DBMS

    题意

    (n)个人名串(s_i),每个串的初始权值为(0),有(m)次询问,询问有两种:

    • (1~i~x),将第(i)个串的权值改为(x)
    • (2~q),给一个字符串(q),问(q)中出现的所有人名串的权值的最大值,没出现输出(-1)

    (n,mle 3 cdot 10^5, sum|s_i| le 3 cdot 10^5,sum|q| le 3 cdot 10^5,xle 10^9)

    分析

    把所有人名插入AC自动机建fail树,一种暴力的做法是对每个终止结点开个multiset记录这个结点的子串的权值,对于修改操作在multiset上修改,查询操作把查询串在AC自动机上跑,对每个结点暴跳fail取得最大值,考虑优化,暴跳fail实际上是从当前结点到根节点的这条fail链上取得最大值,那么我们对fail树进行树链剖分,并用线段树来维护区间最值即可,时间复杂度为(O(nlog^2n))。另一种巧妙的做法是,我们预处理fail链的链头,用(top[u])表示结点(u)往上跳fail遇到的第一个有子串的结点,这样我们就可以同样对每个结点不停的跳到(top[u])就会只跳那些有子串的结点,因为最多有(sqrt{n})种不同长度的人名,所以每次最多跳(sqrt n)次,时间复杂度为(O(n sqrt{n}))

    Code1

    #include<bits/stdc++.h>
    #define rep(i,x,n) for(int i=x;i<=n;i++)
    #define per(i,n,x) for(int i=n;i>=x;i--)
    #define sz(a) int(a.size())
    #define rson mid+1,r,p<<1|1
    #define pii pair<int,int>
    #define lson l,mid,p<<1
    #define ll long long
    #define pb push_back
    #define mp make_pair
    #define se second
    #define fi first
    using namespace std;
    const double eps=1e-8;
    const int mod=1e9+7;
    const int N=3e5+10;
    const int inf=1e9;
    int n,m;
    char s[N];
    int d[N],b[N];
    vector<int>g[N];
    struct SegmentTree{
    	int tr[N<<2],n;
    	int top[N],sz[N],f[N],d[N],son[N],dfn[N],id[N],val[N],tot;
    	void bd(int l,int r,int p){
    		if(l==r) return tr[p]=val[id[l]],void();
    		int mid=l+r>>1;
    		bd(lson);bd(rson);
    		tr[p]=max(tr[p<<1],tr[p<<1|1]);
    	}
    	void up(int x,int l,int r,int p,int k){
    		if(l==r) return tr[p]=k,void();
    		int mid=l+r>>1;
    		if(x<=mid) up(x,lson,k);
    		else up(x,rson,k);
    		tr[p]=max(tr[p<<1],tr[p<<1|1]);
    	}
    	int qy(int dl,int dr,int l,int r,int p){
    		if(l==dl&&r==dr) return tr[p];
    		int mid=l+r>>1;
    		if(dr<=mid) return qy(dl,dr,lson);
    		else if(dl>mid) return qy(dl,dr,rson);
    		else return max(qy(dl,mid,lson),qy(mid+1,dr,rson));
    	}
    	void dfs(int u){
    		d[u]=d[f[u]]+1;
    		sz[u]=1;
    		for(int x:g[u]){
    			f[x]=u;
    			dfs(x);
    			sz[u]+=sz[x];
    			if(sz[x]>sz[son[u]]) son[u]=x;
    		}
    	}
    	void dfs1(int u,int t){
    		top[u]=t;dfn[u]=++tot;
    		id[tot]=u;
    		if(son[u]) dfs1(son[u],t);
    		for(int x:g[u]){
    			if(x==son[u]) continue;
    			dfs1(x,x);
    		}
    	}
    	void up(int i,int k){
    		up(dfn[i],1,n,1,k);
    	}
    	int qy(int x,int y){
    		int ret=-1;
    		while(top[x]!=top[y]){
    			if(d[top[x]]<d[top[y]]) swap(x,y);
    			ret=max(ret,qy(dfn[top[x]],dfn[x],1,n,1));
    			x=f[top[x]];
    		}
    		if(d[x]<d[y]) swap(x,y);
    		return max(ret,qy(dfn[y],dfn[x],1,n,1));
    	}
    	void init(int _n){
    		n=_n;
    		dfs(1);
    		dfs1(1,1);
    		bd(1,n,1);
    	}
    }seg;
    struct ACtree{
        int son[N][26],fail[N],top[N],tot;
        multiset<int>cnt[N];
        int newnode(){
            for(int i=0;i<26;i++) son[tot][i]=0;
            cnt[tot++].clear();
            return tot-1;
        }
        void init(){
            tot=0;
            newnode();
        }
        void ins(int x,char s[]){
            int rt=0,m=strlen(s);
            for(int i=0;i<m;i++){
                if(!son[rt][s[i]-'a']) son[rt][s[i]-'a']=newnode();
                rt=son[rt][s[i]-'a'];
            }
            cnt[rt].insert(0);
            b[x]=rt;
        }
        void gao(){
            queue<int>q;
            for(int i=0;i<26;i++) if(son[0][i]) fail[son[0][i]]=0,q.push(son[0][i]);
            while(!q.empty()){
                int u=q.front();q.pop();
                if(!cnt[fail[u]].empty()) top[u]=fail[u];
                else top[u]=top[fail[u]];
                g[fail[u]+1].pb(u+1);
                for(int i=0;i<26;i++){
                    if(son[u][i]){
                        fail[son[u][i]]=son[fail[u]][i];
                        q.push(son[u][i]);
                    }else son[u][i]=son[fail[u]][i];
                }
            }
            for(int i=0;i<tot;i++) if(!cnt[i].empty()){
            	seg.val[i+1]=0;
            }else seg.val[i+1]=-1;
            seg.init(tot);
        }
        void change(int i,int x){
            cnt[b[i]].erase(cnt[b[i]].lower_bound(d[i]));
            d[i]=x;
            cnt[b[i]].insert(x);
            auto it=cnt[b[i]].end();
            --it;
            seg.up(b[i]+1,*it);
        }
        int qy(char s[]){
            int rt=0,m=strlen(s),ans=-1;
            for(int i=0;i<m;i++){
                rt=son[rt][s[i]-'a'];
                ans=max(ans,seg.qy(rt+1,1));
            }
            return ans;
        }
    }AC;
    int main(){
        scanf("%d%d",&n,&m);
        AC.init();
        for(int i=1;i<=n;i++){
            scanf("%s",s);
            AC.ins(i,s);
        }
        AC.gao();
        while(m--){
            int op,i,x;
            scanf("%d",&op);
            if(op==1){
                scanf("%d%d",&i,&x);
                AC.change(i,x);
            }else{
                scanf("%s",s);
                printf("%d
    ",AC.qy(s));
            }
        }
        return 0;
    }
    

    Code2

    #include<bits/stdc++.h>
    #define rep(i,x,n) for(int i=x;i<=n;i++)
    #define per(i,n,x) for(int i=n;i>=x;i--)
    #define sz(a) int(a.size())
    #define rson mid+1,r,p<<1|1
    #define pii pair<int,int>
    #define lson l,mid,p<<1
    #define ll long long
    #define pb push_back
    #define mp make_pair
    #define se second
    #define fi first
    using namespace std;
    const double eps=1e-8;
    const int mod=1e9+7;
    const int N=3e5+10;
    const int inf=1e9;
    int n,m;
    char s[N];
    int d[N],b[N];
    struct ACtree{
        int son[N][26],fail[N],top[N],tot;
        multiset<int>cnt[N];
        int newnode(){
            for(int i=0;i<26;i++) son[tot][i]=0;
            cnt[tot++].clear();
            return tot-1;
        }
        void init(){
            tot=0;
            newnode();
        }
        void ins(int x,char s[]){
            int rt=0,m=strlen(s);
            for(int i=0;i<m;i++){
                if(!son[rt][s[i]-'a']) son[rt][s[i]-'a']=newnode();
                rt=son[rt][s[i]-'a'];
            }
            cnt[rt].insert(0);
            b[x]=rt;
        }
        void gao(){
            queue<int>q;
            for(int i=0;i<26;i++) if(son[0][i]) fail[son[0][i]]=0,q.push(son[0][i]);
            while(!q.empty()){
                int u=q.front();q.pop();
                if(!cnt[fail[u]].empty()) top[u]=fail[u];
                else top[u]=top[fail[u]];
                for(int i=0;i<26;i++){
                    if(son[u][i]){
                        fail[son[u][i]]=son[fail[u]][i];
                        q.push(son[u][i]);
                    }else son[u][i]=son[fail[u]][i];
                }
            }
        }
        void change(int i,int x){
            cnt[b[i]].erase(cnt[b[i]].lower_bound(d[i]));
            d[i]=x;
            cnt[b[i]].insert(x);
        }
        int qy(char s[]){
            int rt=0,m=strlen(s),ans=-1;
            for(int i=0;i<m;i++){
                rt=son[rt][s[i]-'a'];
                for(int j=rt;j;j=top[j]){
                    if(!cnt[j].empty()){
                        auto it=cnt[j].end();
                        --it;
                        ans=max(ans,*it);
                    }
                }
            }
            return ans;
        }
    }AC;
    int main(){
        scanf("%d%d",&n,&m);
        AC.init();
        for(int i=1;i<=n;i++){
            scanf("%s",s);
            AC.ins(i,s);
        }
        AC.gao();
        while(m--){
            int op,i,x;
            scanf("%d",&op);
            if(op==1){
                scanf("%d%d",&i,&x);
                AC.change(i,x);
            }else{
                scanf("%s",s);
                printf("%d
    ",AC.qy(s));
            }
        }
        return 0;
    }
    
  • 相关阅读:
    并查集(Java实现)
    Flask入门HelloWorld
    归并排序及优化(Java实现)
    用IDEA生成javadoc文档
    windows下安装Virtualenvwrapper
    模板方法模式Template Method(Java实现)
    部署Flask项目到腾讯云服务器CentOS7
    冒泡排序及优化(Java实现)
    迭代器模式Iterator(Java实现)
    堆排序(Java数组实现)
  • 原文地址:https://www.cnblogs.com/xyq0220/p/13896929.html
Copyright © 2020-2023  润新知