Educational Codeforces Round 97 (Rated for Div. 2) G. Death DBMS (AC自动机)

传送门
G. Death DBMS
time limit per test2 seconds
memory limit per test512 megabytes
inputstandard input
outputstandard output
For the simplicity, let’s say that the “Death Note” is a notebook that kills a person when their name is written in it.

It’s easy to kill with it, but it’s pretty hard to keep track of people you haven’t killed and still plan to. You decided to make a “Death Database Management System” — a computer program that provides the easy access to the database of possible victims. Let me describe its specifications to you.

Let’s define a victim entity: a victim has a name (not necessarily unique) that consists only of lowercase Latin letters and an integer suspicion value.

At the start of the program the user enters a list of n victim names into a database, each suspicion value is set to 0.

Then the user makes queries of two types:

1 i x — set the suspicion value of the i-th victim to x;
2 q — given a string q find the maximum suspicion value of a victim whose name is a contiguous substring of q.
Just to remind you, this program doesn’t kill people, it only helps to search for the names to write down in an actual notebook. Thus, the list of the victims in the database doesn’t change throughout the queries.

What are you waiting for? Write that program now!

Input
The first line contains two integers n and m (1≤n,m≤3⋅105) — the number of victims and the number of queries, respectively.

Each of the next n lines contains a single string si — the name of the i-th victim. Each name consists only of lowercase Latin letters.

Each of the next m lines contains a query of one of two types:

1 i x (1≤i≤n, 0≤x≤109) — change the suspicion value of the i-th victim to x;
2 q — given a string q consisting only of lowercase Latin letters find the maximum suspicion value of a victim whose name is a contiguous substring of q.
There is at least one query of the second type. The total length of the strings si doesn’t exceed 3⋅105. The total length of the strings q doesn’t exceed 3⋅105.

Output
For each query of the second type print an integer value. If there is no victim name that is a contiguous substring of q, then print −1. Otherwise, print the maximum suspicion value of a victim whose name is a contiguous substring of q.

Examples
5 8
kurou
takuo
takeshi
naomi
shingo
2 nakiraomi
2 abanaomicaba
1 3 943
2 takuotakeshishingo
1 5 135832
2 shingotakeshi
1 5 0
2 shingotakeshi

-1
0
943
135832
943

题意

给你n,q(n,q<=3 ⋅ \cdot 105),再给你n个只由小写字母组成的单词,再给你q次操作,每次操作有两种类型:
1 i x 将第i个单词的权值变为x (每个单词的权值初始为0)
2 s 查询所有为串s子串的单词中的最大权值。如果所有单词里没有这个串的子串,输出-1
所有单词的总长度不超过3 ⋅ \cdot 105,第二种查询的所有s总长度不超过3 ⋅ \cdot 105

思路

第一种做法: 如果对所有单词建立AC自动机,那么第二种查询相当于查询s的对应的所有节点到fail树根的路径上的权值最大值,第一种操作就是(fail树上点权的)单点修改,这种单点修改和区间查询可以用树链剖分来做。
第二种做法:
依然是对所有单词建立AC自动机,但是发现对答案有贡献的只有trie树上每个单词的结尾节点(用一个multiset存每个尾结点的所有权值,因为可能有重复的单词所以是multiset),因此我们在建立fail树的时候再开一个nxt数组,直接指向fail树上上一个结尾节点(有贡献的点),这样最坏情况下是查询 n \sqrt n n 个长度为 n \sqrt n n 的s串,每个串最多在fail树上跳 n \sqrt n n 次,所以总复杂度是 O ( n n ) O(n\sqrt n) O(nn ) n n n q q q同阶)

#include<bits/stdc++.h>
#define ll long long
#define inf 0x3f3f3f3f
#define rep(i,a,b) for(int i=(a);i<=(b);i++)
#define dep(i,a,b) for(int i=(a);i>=(b);i--)
#define ls (rt<<1)
#define rs (rt<<1|1)
#define fi first
#define se second
#define pb push_back
using namespace std;
const int maxn=3e5+5;
//const double pi=acos(-1.0);
//const double eps=1e-9;
//const ll mo=1e9+7;
int n,m,k;
int a[maxn],c[maxn];
int ans,tmp,cnt;
int flag;
char s[maxn];
template <typename T>
inline void read(T &X){
    X=0;int w=0; char ch=0;
    while(!isdigit(ch)) {w|=ch=='-';ch=getchar();}
    while(isdigit(ch)) X=(X<<3)+(X<<1)+(ch^48),ch=getchar();
    if(w) X=-X;
}
struct ACzdj{
    int ch[maxn][26];
    int fail[maxn];
    int nxt[maxn];
    multiset<int>st[maxn];
    int stk[maxn],ta;
    bool ok[maxn];
    int cnt;
    void init(){
        cnt=0;
        memset(ch[0],0,sizeof(ch[0]));
        st[0].clear();
        ok[0]=0;
    }
    int add(char *s,int val){
        int len=strlen(s),u=0;
        rep(i,0,len-1){
            int id=s[i]-'a';
            if(!ch[u][id]) {
                ch[u][id]=++cnt;
                memset(ch[cnt],0,sizeof(ch[cnt]));
                st[cnt].clear();
                ok[cnt]=0;
            }
            u=ch[u][id];
        }
        st[u].insert(val);
        return u;
    }
    void build(){
        queue<int>q;
        int u=0;
        rep(i,0,25) if(ch[u][i]){
            fail[ch[u][i]]=0;
            nxt[ch[u][i]]=0;
            q.push(ch[u][i]);
        }
        while(!q.empty()){
            int u=q.front();q.pop();
            rep(i,0,25){
                if(ch[u][i]) {
                    fail[ch[u][i]]=ch[fail[u]][i];
                    nxt[ch[u][i]]=(st[ch[fail[u]][i]].size()>0?ch[fail[u]][i]:nxt[ch[fail[u]][i]]);
                    q.push(ch[u][i]);
                }
                else ch[u][i]=ch[fail[u]][i];
            }
        }
    }
    int query(char *s){
        int ans = -1;
        int len=strlen(s),u=0;
        ta=0;
        rep(i,0,len-1){
            int id=s[i]-'a';
            u=ch[u][id];
            for(int j=u;j&&!ok[j];j=nxt[j]){
                //cout<<"!!: "<<nxt[j]<<endl;
                if(st[j].size()) ans=max(ans,*st[j].rbegin());
                ok[j]=1;
                stk[++ta]=j;
            }
        }
        while(ta) ok[stk[ta--]]=0;
        return ans;
    }
}ac;
void solve(){
    read(n); read(m);
    ac.init();
    rep(i,1,n){
        scanf("%s",s);
        a[i]=ac.add(s,0);
        c[i]=0;
    }
    ac.build();
    rep(i,1,m){
        int id;
        read(id);
        if(id==1){
            int x,val;
            read(x); read(val);
            ac.st[a[x]].erase(ac.st[a[x]].find(c[x]));
            ac.st[a[x]].insert(val);
            c[x]=val;
        }
        else {
            scanf("%s",s);
            int ans=ac.query(s);
            printf("%d\n",ans);
        }
    }
}
int main(){
/*
#ifdef ONLINE_JUDGE
#else
    freopen("D:/Temp/in.txt", "r", stdin);
#endif
*/
    // freopen("e://duipai//myout.txt","w",stdout);
    int T=1,cas=1;
    //read(T);
    while(T--){
        solve();
    }
    //system("pause");
    return 0;
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
"educational codeforces round 103 (rated for div. 2)"是一个Codeforces平台上的教育性比赛,专为2级选手设计评级。以下是有关该比赛的回答。 "educational codeforces round 103 (rated for div. 2)"是一场Codeforces平台上的教育性比赛。Codeforces是一个为程序员提供竞赛和评级的在线平台。这场比赛是专为2级选手设计的,这意味着它适合那些在算法和数据结构方面已经积累了一定经验的选手参与。 与其他Codeforces比赛一样,这场比赛将由多个问题组成,选手需要根据给定的问题描述和测试用例,编写程序来解决这些问题。比赛的时限通常有两到三个小时,选手需要在规定的时间内提交他们的解答。他们的程序将在Codeforces的在线评测系统上运行,并根据程序的正确性和效率进行评分。 该比赛被称为"educational",意味着比赛的目的是教育性的,而不是针对专业的竞争性。这种教育性比赛为选手提供了一个学习和提高他们编程技能的机会。即使选手没有在比赛中获得很高的排名,他们也可以从其他选手的解决方案中学习,并通过参与讨论获得更多的知识。 参加"educational codeforces round 103 (rated for div. 2)"对于2级选手来说是很有意义的。他们可以通过解决难度适中的问题来测试和巩固他们的算法和编程技巧。另外,这种比赛对于提高解决问题能力,锻炼思维和提高团队合作能力也是非常有帮助的。 总的来说,"educational codeforces round 103 (rated for div. 2)"是一场为2级选手设计的教育性比赛,旨在提高他们的编程技能和算法能力。参与这样的比赛可以为选手提供学习和进步的机会,同时也促进了编程社区的交流与合作。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值