Educational Codeforces Round 97 G. Death DBMS题解

传送门

前言

这是我第一次在cf比赛时做出AC自动机的题,而且是在比赛最后30秒AC的,特发博客纪念一波。

题意


中文简单说一下就是:有n个字符串,初始值为0。有两种操作,操作1是将序号为i的字符串的值赋为x,操作2是找到所有是字符串t的子串的字符串的值的最大值。

题解

多串匹配问题很显然是个AC自动机问题,如果这题没有两个相同的串就几乎是一道模板题,只要在建trie时记录每个串对应的节点,修改时直接修改对应节点即可,查询时遍历后缀链接找出最大值即可。但如果有多个串相同,可能同一节点会有多个串与之对应,如果我们还是用val[ ]存储每个节点对应串的最大值,就要在每次修改中找到该点对应的所有串中的最大值(所以我们对每个节点建立一棵线段树)。我的做法是,对每个节点开一个pair型的优先队列,第一关键字存储数值,第二关键字存储对应字符编号,每次修改在对应节点加入pair(x,i),再根据该节点的优先队列值修改其val值。具体地,取出当前节点优先队列的首元素,如果首元素的i值已经不对应x值了,就pop出去,重复这一过程,否则x值为所有对应串的最大值。因为每次修改最多入队一次、出队一次,所以总修改时间复杂度为\(O(Q\log Q)\)。而查询操作与普通AC自动机一样,于是总时间复杂度为\(O(N+Q\log Q)\)

代码

/*************************************************************************
	> File Name: 2.cpp
	> Author: Knowledge_llz
	> Mail: 925538513@qq.com 
	> Blog: https: https://www.cnblogs.com/Knowledge-Pig/ 
	> Created Time: 2020/10/26 23:11:01
 ************************************************************************/

#include<bits/stdc++.h>
#define For(i,a,b) for(register int i=(a);i<=(b);++i)
#define LL long long
#define pb push_back
#define fi first
#define se second
#define pr pair<int,int>
#define mk(a,b) make_pair(a,b)
using namespace std;
int read(){
	char x=getchar(); int u=0,fg=0;
	while(!isdigit(x)){ if(x=='-') fg=1; x=getchar(); }
	while(isdigit(x)){ u=(u<<3)+(u<<1)+(x^48); x=getchar(); }
	return fg?-u:u;
}
const int maxx=1e6+10;
char s[maxx],t[maxx];
int n,m,pos[maxx],sp[maxx];
priority_queue<pr>que[maxx];
struct Trie{
	int ch[maxx][30],val[maxx],f[maxx],last[maxx],sz;
	Trie(){ sz=1; memset(ch[0],0,sizeof(ch[0])); }
	int idx(char c){ return c-'a'; }
	void insert(char *T,int id){
		int u=0,len=strlen(T);
		for(int i=0;i<len;++i){
			int c=idx(T[i]);
			if(!ch[u][c]){
				memset(ch[sz],0,sizeof(ch[sz]));
				val[sz]=-1;
				ch[u][c]=sz++;
			}
			u=ch[u][c];
		}
		val[u]=0;
		pos[id]=u;
		que[u].push(pr(0,id));
	}
	void getfail(){				
		queue<int>q;		
		f[0]=0;
		For(c,0,25){
			int u=ch[0][c];
			if(u){
				q.push(u);
				f[u]=0;
			}
		}
		while(!q.empty()){
			int r=q.front(); q.pop();
			For(c,0,25){
				int u=ch[r][c];
				if(!u)  ch[r][c]=ch[f[r]][c];
				else{
					q.push(u);
					f[u]=ch[f[r]][c];
					last[u]=(val[f[u]]>=0)?f[u]:last[f[u]];
				}
			}
		}
	}
	int Find(char *T){			
		int len=strlen(T);
		int j=0,ans=-1;
		For(i,0,len-1){
			int c=idx(T[i]);
			j=ch[j][c];
			for(int x=j;x;x=last[x]){
				ans=max(val[x],ans);
			}
		}
		return ans;
	}
}trie;


int main()
{
#ifndef ONLINE_JUDGE
	freopen("input.in", "r", stdin);
	freopen("output.out", "w", stdout);
#endif
	n=read(); m=read();
	For(i,1,n){
		scanf("%s",t);
		trie.insert(t,i);
	}
	trie.getfail();
	while(m--){
		int o=read();
		if(o==1){
			int u=read(),v=read(),z=pos[u];
			sp[u]=v;
			que[z].push(pr(v,u));
			while(!que[z].empty()){
				int x=que[z].top().fi,y=que[z].top().se;
				if(sp[y]==x) break;
				else que[z].pop();
			}
			trie.val[z]=que[z].top().fi;
		}
		else{
			scanf("%s",t);
			printf("%d\n",trie.Find(t));
		}
	}
	return 0;
}
posted @ 2020-10-30 11:41  Knowledge-Pig  阅读(113)  评论(0)    收藏  举报