CF1437G Death DBMS(AC自动机,目前还是TLE)

洛谷链接:Death DBMS - 洛谷 

解法:考虑朴素的AC自动机,注意由于字符串会重复,需要用multiset来记录val,这个代码TLE在第87个点。

#include<bits/stdc++.h>
using namespace std;
const int maxn=3e5+5;
int ch[maxn][26],fail[maxn],tot,ed_pos[maxn], val[maxn]; //ed_pos数组用来记录每个字符串结束位置,val数组用来记录每个s的val
multiset<int> st[maxn]; //记录所有val
int n,m; string s;
string ss[maxn];

inline void build(int idx, const string&s){
    int len=s.size(), x, u=0;
    for(int i=0; i<len; i++){
        x=s[i]-'a';
        if(!ch[u][x]) ch[u][x] = ++tot; //如果没有这个点,就建立
        u=ch[u][x];
    }
    ed_pos[idx]=u; //记录结束位置
    st[u].insert(0);
    val[idx] = 0;
}
inline void get_fail(){
    queue<int> q;
    for(int i=0; i<26; i++) //特别处理第一层
        if(ch[0][i]) q.push(ch[0][i]); //第一层结点加入队列
    while(q.size()){ //bfs求fail指针
        int u=q.front(); q.pop(); //父结点
        for(int i=0; i<26; i++){
            if(ch[u][i]){ //有这个子结点
                fail[ch[u][i]] = ch[fail[u]][i]; //fail = fafail->child
                q.push(ch[u][i]);
            } else {ch[u][i] = ch[fail[u]][i];} //特殊处理,建立虚拟子结点,实际上相当于失配
        }
    }
}
inline void change(int x,int y){
    int u = ed_pos[x];
    st[u].erase(st[u].find(val[x]));
    st[u].insert(y);
    val[x] = y; //最后别忘记把val数组里的改了
}
inline void ask(const string&s){
    int u=0, res=-1;
    for(char c:s){
        u=ch[u][c-'a'];
        for(int t=u; t; t=fail[t]){
            if(st[t].size()) res=max(res,*st[t].rbegin());
        }
    }
    cout<<res<<'\n';
}
int main(){
    ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
	memset(val,-1,sizeof(val));
	cin>>n>>m; for(int i=1; i<=n; i++) {cin>>s; ss[i]=s; build(i,s);}
	get_fail();
	for(int i=1; i<=m; i++){
        int q,x,y; cin>>q;
        if(q==1) {cin>>x>>y; change(x,y);}
        else {cin>>s; ask(s);}
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值