歌名 - 歌手
0:00

    NOIP2017提高A组模拟10.6】Biology

    题目

    这里写图片描述

    trie

    暴力就是对于每个询问的T个字符串
    第i个和第i+1个直接个从后暴力枚举每位是否相同,
    但这个方法TLE
    我们考虑是否可以用更快的方法来求出两个字符串的最长公共后缀。
    我们把所有的字符串从后往前扔进trie中,搞个lca就可以了,最长公共后缀就是lca的深度。

    #include <cmath>
    #include <iostream>
    #include <cstdio>
    #include <cstdlib>
    #include <cstring>
    #include <algorithm>
    #include <queue>
    #include <map>
    const int maxlongint=2147483647;
    const int mo=1e9+7;
    const int N=1000105;
    using namespace std;
    struct trie
    {
    	int a[27],deep;
    }tr[N];
    int n,m,ans,rt[N],tot,len,le,g[N][23],lo;
    char s[N];
    int lca(int x,int y)
    {
    	if(tr[x].deep>tr[y].deep) swap(x,y);
    	for(int j=lo;j>=0;j--)
    		if(tr[g[y][j]].deep>=tr[x].deep) y=g[y][j];
    	if(x==y) return tr[x].deep;
    	for(int j=lo;j>=0;j--)
    		if(g[y][j]!=g[x][j]) x=g[x][j],y=g[y][j];
    	return tr[g[x][0]].deep;
    }
    int put(int x)
    {
    	int now=1;
    	for(int i=x;i>=1;i--)
    	{
    		int t=tr[now].a[s[i]-'a'];
    		if(t) now=t;
    		else 
    		{
    			tr[tr[now].a[s[i]-'a']=++tot].deep=tr[now].deep+1,g[tot][0]=now,now=tot;
    			for(int j=1;j<=lo;j++) g[now][j]=g[g[now][j-1]][j-1];
    		}
    	}
    	return now;
    }
    int main()
    {
    	scanf("%d%d",&n,&m);
    	lo=20;
    	tr[++tot].deep=1;
    	for(int i=1;i<=n;i++)
    	{
    		scanf("%s",s+1);
    		int len=strlen(s+1);
    		rt[i]=put(len);
    	}
    	for(int i=1;i<=m;i++)
    	{
    		int t;
    		scanf("%d",&t);
    		if(t==1)
    		{
    			scanf("%s",s+1);
    			int len=strlen(s+1);
    			rt[++n]=put(len);
    		}
    		else
    		{
    			int T,TU[12],ans=maxlongint;
    			scanf("%d",&T);
    			for(int j=1;j<=T;j++) scanf("%d",&TU[j]);
    			for(int j=1;j<=T-1;j++) ans=min(lca(rt[TU[j]],rt[TU[j+1]]),ans);
    			printf("%d\n",ans-1);
    		}
    	}
    }
    
    
    posted @ 2018-05-23 21:44  无尽的蓝黄  阅读(209)  评论(0编辑  收藏  举报