欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

JZOJ5397. 【NOIP2017提高A组模拟10.6】Biology

程序员文章站 2022-07-14 15:21:29
...

JZOJ5397. 【NOIP2017提高A组模拟10.6】Biology

题解

如果我们将全部字符串倒过来,
那么后缀就变成了前缀。

如果用这些倒过来的字符串的建一棵tire,
最长公共前缀就是每一个字符串的最后一个点的lca的深度。

查询就用倍增+lca实现,
对应每加入一个新的节点,就处理一下它的父亲。

code

#include<queue>
#include<cstdio>
#include<iostream>
#include<algorithm>
#include <cstring>
#include <string.h>
#include <cmath>
#include <math.h>
#define ll long long
#define N 1000003
#define db double
#define P putchar
#define G getchar
#define mo 998244353
using namespace std;
char ch;
void read(int &n)
{
    n=0;
    ch=G();
    while((ch<'0' || ch>'9') && ch!='-')ch=G();
    ll w=1;
    if(ch=='-')w=-1,ch=G();
    while('0'<=ch && ch<='9')n=(n<<3)+(n<<1)+ch-'0',ch=G();
    n*=w;
}

ll max(ll a,ll b){return a>b?a:b;}
ll min(ll a,ll b){return a<b?a:b;}
ll abs(ll x){return x<0?-x:x;}
void write(ll x){if(x>9) write(x/10);P(x%10+'0');}

struct node
{
    int son[26];
}tr[N];

int n,m,f[N][20],deep[N];
int tot,t,k,a[N],x,pos[N];
char s[N];

int lca(int x,int y)
{
    if(deep[x]>deep[y])swap(x,y);
    for(int j=19;j>=0;j--)
        if(deep[x]<=deep[f[y][j]])y=f[y][j];
    if(x==y)return x;
    for(int j=19;j>=0;j--)
        if(f[x][j]!=f[y][j])x=f[x][j],y=f[y][j];
    return f[x][0];
}

int ins(char* s,int len)
{
    int x=1;
    for(int p=1;p<=len;p++)
    {
        if(tr[x].son[s[p]-'a']==0)
        {
            deep[++tot]=deep[x]+1;
            tr[x].son[s[p]-'a']=tot;
            f[tot][0]=x;
            for(int j=1;j<20;j++)
                f[tot][j]=f[f[tot][j-1]][j-1];
        }
        x=tr[x].son[s[p]-'a'];
    }
    return x;
}

int main()
{
    freopen("biology.in","r",stdin);
    freopen("biology.out","w",stdout);
    read(n);read(m);deep[1]=tot=1;
    for(int i=1;i<=n;i++)
    {
        ch=G();
        while(ch<'a' || ch>'z')ch=G();x=0;
        while('a'<=ch && ch<='z')s[++x]=ch,ch=G();
        for(int j=1;j<=x/2;j++)
            swap(s[j],s[x-j+1]);
        pos[i]=ins(s,x);
    }
    for(int i=1;i<=m;i++)
    {
        read(t);
        if(t==1)
        {
            ch=G();
            while(ch<'a' || ch>'z')ch=G();x=0;
            while('a'<=ch && ch<='z')s[++x]=ch,ch=G();
            for(int j=1;j<=x/2;j++)
                swap(s[j],s[x-j+1]);
            pos[++n]=ins(s,x);
        }
        else
        {
            read(k);read(t);t=pos[t];
            for(int j=2;j<=k;j++)
                read(x),t=lca(t,pos[x]);
            write(deep[t]-1),P('\n');
        }
    }
}
相关标签: 最近公共祖先