Biology 题解

Biology 题解

题意简述

初始有\(n\)个字符串,有\(m\)个操作,操作分为两种:

  1. 插入一个新的字符串,下标递增(\(n+1,n+2,n+3\dots\))。
  2. 查询\(k\)个字符串\(x_1,x_2,\dots,x_k\)的最长公共后缀长度。

\(N\le50000,M\le100000,2\le T\le10,|S_i|\le10000,\sum|S_i|\le1000000,总字符串数量\le100000\)

image-20201126094924014

Solution

的确是百年难得一见的水题。

先将字符串反转,变成一个最长公共前缀问题。

暴力是肯定不行的,这个显然要\(\log\)才过得去。

所以使用\(trie\)维护前缀,\(LCA\)查询最长公共前缀。

最长公共前缀的深度就是公共前缀的长度。

Code

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<map>
#include<set>
#include<queue>
#include<vector>
#define IL inline
#define re register
#define LL long long
#define ULL unsigned long long
#ifdef TH
#define debug printf("Now is %d\n",__LINE__);
#else
#define debug
#endif
using namespace std;

template<class T>inline void read(T&x)
{
    char ch=getchar();
    int fu;
    while(!isdigit(ch)&&ch!='-') ch=getchar();
    if(ch=='-') fu=-1,ch=getchar();
    x=ch-'0';ch=getchar();
    while(isdigit(ch)){x=x*10+ch-'0';ch=getchar();}
    x*=fu;
}
inline int read()
{
	int x=0,fu=1;
    char ch=getchar();
    while(!isdigit(ch)&&ch!='-') ch=getchar();
    if(ch=='-') fu=-1,ch=getchar();
    x=ch-'0';ch=getchar();
    while(isdigit(ch)){x=x*10+ch-'0';ch=getchar();}
    return x*fu;
}
int G[55];
template<class T>inline void write(T x)
{
    int g=0;
    if(x<0) x=-x,putchar('-');
    do{G[++g]=x%10;x/=10;}while(x);
    for(int i=g;i>=1;--i)putchar('0'+G[i]);putchar('\n');
}
int n,m;
string reverse(string str)
{
	for(int i=0;i<str.size()/2;i++)
	{
		swap(str[i],str[str.size()-i-1]);
	}
//	cout<<str<<endl;
	return str;
}
struct Trie
{
	int ch[1000010][26];
	int cnt;
	int v[100010];//将字符串编号映射到其末尾的节点 
	int dep[1000010],f[1000010][17];
	Trie()
	{
		cnt=1;
		memset(ch,0,sizeof(ch));
		memset(v,0,sizeof(v));
	}
	void insert(string str,int pos)
	{
		int u=1;
		for(int i=0;i<str.size();i++)
		{
			if(!ch[u][str[i]-'a']) ch[u][str[i]-'a']=++cnt;
			dep[ch[u][str[i]-'a']]=dep[u]+1;
			f[ch[u][str[i]-'a']][0]=u;
			u=ch[u][str[i]-'a'];
			for(int i=1;i<=16;i++) f[u][i]=f[f[u][i-1]][i-1];
		}
		v[pos]=u;
	}
	int LCA(int x,int y)
	{
		if(dep[x]<dep[y]) swap(x,y);
		for(int i=16;i>=0;i--)
		{
			if(dep[f[x][i]]>=dep[y]) x=f[x][i];
		}
		if(x==y) return x;
		for(int i=16;i>=0;i--)
		{
			if(f[x][i]!=f[y][i]) x=f[x][i],y=f[y][i];
		}
		return f[x][0];
	}
}trie;
int main()
{
//	freopen("biology.in","r",stdin);
//	freopen("biology.out","w",stdout);
	n=read();
	m=read();
	string t;
	for(int i=1;i<=n;i++) cin>>t,trie.insert(reverse(t),i);
	int op,x,y;
	while(m--)
	{
		op=read();
		if(op==1)
		{
			cin>>t;
			trie.insert(reverse(t),++n);
		}
		else
		{
			x=read();
			y=trie.v[read()];
			for(int i=2;i<=x;i++)
			{
				y=trie.LCA(y,trie.v[read()]);
			}
			write(trie.dep[y]);
		}
	}
	return 0;
}
/*
5 5
zzj
pri
prime
ime
owaski
2 3 1 3 5
2 2 2 3
1 actri
2 2 3 4
2 3 2 6 5
*/
posted @ 2020-11-26 12:17  Vanilla_chan  阅读(111)  评论(0)    收藏  举报