HDU 5069 Harry And Biological Teacher(AC自动机+线段树)

题意

给定 \(n\) 个字符串,\(m\) 个询问,每次询问 \(a\) 字符串的后缀和 \(b\) 字符串的前缀最多能匹配多长。

\(1\leq n,m \leq 10^5\)

思路

多串匹配,考虑 \(\text{AC}\)自动机,对 \(n\) 个串建自动机,观察这个结构,不难发现 \(Trie\) 树的结构和前缀有关,\(fail\) 树的结构和后缀有关。

考虑离线,对于每个 \(b\) ,存储它对应的 \(a\) ,我们通过在自动机上扫 \(b\) 来回答。由于扫到某节点 \(u\) ,在 \(fail\) 树上 \(u\) 的子节点都能得到 \(u\) 在 \(Trie\) 树上深度的贡献,最后对每一个 \(a\),查询它在自动机位置上的贡献最大值即可 。用线段树维护 \(fail\) 树的 \(\text{dfs}\) 序,区间修改最大值,单点查询最大值。

\(\text{AC}\)自动机上有 \(Trie,fail\) 两棵树,分别包含前后缀的信息,这类问题可以通过 \(\text{AC}\)自动机,转化为树上问题。

代码

#include<bits/stdc++.h>
#define FOR(i,x,y) for(int i=(x),i##END=(y);i<=i##END;++i)
#define DOR(i,x,y) for(int i=(x),i##END=(y);i>=i##END;--i)
#define x first
#define y second
typedef long long LL;
using namespace std;
typedef pair<int,int> pii;
const int N=1e5+5;
const int NN=N*22;
int c_d[256];
template<const int maxn,const int maxm>struct Linked_list
{
    int head[maxn],to[maxm],nxt[maxm],tot;
    Linked_list(){clear();}
    void clear(){memset(head,-1,sizeof(head));tot=0;}
    void add(int u,int v){to[++tot]=v,nxt[tot]=head[u],head[u]=tot;}
    #define EOR(i,G,u) for(int i=G.head[u];~i;i=G.nxt[i])
};
struct SegmentTree
{
    int lson[NN],rson[NN],tag[NN];
    int rt,tot;
    void build()
    {
        tag[0]=lson[0]=rson[0]=0;
        rt=tot=0;
    }
    void create(int &k)
    {
        if(!k)
        {
            k=++tot;
            tag[k]=lson[k]=rson[k]=0;
        }
    }
    void update(int &k,int L,int R,int val,int l,int r)
    {
        create(k);
        if(L<=l&&r<=R){tag[k]=max(tag[k],val);return;}
        int mid=(l+r)>>1;
        if(L<=mid)update(lson[k],L,R,val,l,mid);
        if(R>mid)update(rson[k],L,R,val,mid+1,r);
    }
    int query(int k,int x,int l,int r)
    {
        if(l==r)return tag[k];
        int mid=(l+r)>>1;
        if(x<=mid)return max(query(lson[k],x,l,mid),tag[k]);
        else return max(query(rson[k],x,mid+1,r),tag[k]);
    }
}ST;
Linked_list<N,N>G;
int L[N],R[N],ord;
int ch[N][4],f[N],dep[N];
string P[N];
int rt,tot;
vector<pii>Qry[N];int Ans[N];
char str[N];
int idx[N];
int n,q;

void build(){rt=tot=0;}
void create(int &k)
{
    if(!k)
    {
        k=++tot;
        FOR(i,0,3)ch[k][i]=0;
    }
}
void insert(int &k,string &str,int id)
{
    create(k);
    int now=k;dep[now]=0;
    FOR(i,0,str.length()-1)
    {
        create(ch[now][c_d[(int)str[i]]]);
        now=ch[now][c_d[(int)str[i]]];
        dep[now]=i+1;
    }
    idx[id]=now;
}
void get_fail()
{
    queue<int>Q;
    while(!Q.empty())Q.pop();
    f[rt]=rt;
    FOR(i,0,3)
    {
        if(ch[rt][i])f[ch[rt][i]]=rt,Q.push(ch[rt][i]);
        else ch[rt][i]=rt;
    }
    while(!Q.empty())
    {
        int u=Q.front();Q.pop();
        FOR(i,0,3)
        {
            if(ch[u][i])f[ch[u][i]]=ch[f[u]][i],Q.push(ch[u][i]);
            else ch[u][i]=ch[f[u]][i];
        }
    }
}
void dfs_fail(int u)
{
    L[u]=++ord;
    EOR(i,G,u)dfs_fail(G.to[i]);
    R[u]=ord;
}
void query(int k,string &str,vector<pii>&vec)
{
    ST.build();
    int now=k;
    ST.update(ST.rt,L[now],R[now],dep[now],1,tot);
    FOR(i,0,str.length()-1)
    {
        now=ch[now][c_d[(int)str[i]]];
        ST.update(ST.rt,L[now],R[now],dep[now],1,tot);
    }
    FOR(i,0,(int)vec.size()-1)Ans[vec[i].y]=ST.query(ST.rt,vec[i].x,1,tot);
}

int main()
{
    c_d[(int)'A']=0,c_d[(int)'C']=1,c_d[(int)'G']=2,c_d[(int)'T']=3;
    while(~scanf("%d%d",&n,&q))
    {
        G.clear(),build();
        FOR(i,1,n)Qry[i].clear();
        FOR(i,1,n)
        {
            cin>>P[i];
            insert(rt,P[i],i);
        }
        get_fail();
        FOR(i,1,tot)if(f[i]!=i)G.add(f[i],i);
        ord=0;dfs_fail(rt);

        FOR(i,1,q)
        {
            int a,b;
            scanf("%d%d",&a,&b);
            Qry[b].push_back(pii(L[idx[a]],i));
        }
        FOR(i,1,n)query(rt,P[i],Qry[i]);
        FOR(i,1,q)printf("%d\n",Ans[i]);
    }
    return 0;
}

原文地址:https://www.cnblogs.com/Paulliant/p/10229249.html

时间: 2024-10-07 12:16:17

HDU 5069 Harry And Biological Teacher(AC自动机+线段树)的相关文章

hdu 5069 Harry And Biological Teacher

Harry And Biological Teacher Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 38    Accepted Submission(s): 6 Problem Description As we all know, Harry Porter learns magic at Hogwarts School. How

HDU4117 GRE WORDS(AC自动机+线段树维护fail树的dfs序)

Recently George is preparing for the Graduate Record Examinations (GRE for short). Obviously the most important thing is reciting the words. Now George is working on a word list containing N words. He has so poor a memory that it is too hard for him

HDU 3065 病毒侵袭持续中 AC自动机题解

其实本题比HDU的病毒侵袭1还简单,不过有一个陷阱卡到我了:就是搜索text的时候,当遇到的字母不是大写字母的时候,那么就要重新从根节点开始搜索,否则就会答案错误. 那么一点陷阱,居然没想到啊. 教训啊:看来对不太平常的地方,需要更加深入的思考,才能发现其中的陷阱,否则就WA了. #include <stdio.h> #include <string.h> #include <queue> using std::queue; const int MAX_N = 1001

HDU 3341 Lost&#39;s revenge(AC自动机+状压DP)

Lost's revenge Time Limit: 15000/5000 MS (Java/Others)    Memory Limit: 65535/65535 K (Java/Others)Total Submission(s): 4548    Accepted Submission(s): 1274 Problem Description Lost and AekdyCoin are friends. They always play "number game"(A bor

hdu 3056 病毒侵袭持续中 AC自动机

http://acm.hdu.edu.cn/showproblem.php?pid=3065 刘汝佳的模板真的很好用,这道题直接过 学到: cnt数组记录单词出现次数 以及map存储单词编号与字符串,便于处理相关信息 上代码: #include <cstdio> #include <cstring> #include <algorithm> #include <iostream> #include <queue> #include <str

BZOJ 题目3172: [Tjoi2013]单词(AC自动机||AC自动机+fail树||后缀数组暴力||后缀数组+RMQ+二分等五种姿势水过)

3172: [Tjoi2013]单词 Time Limit: 10 Sec  Memory Limit: 512 MB Submit: 1890  Solved: 877 [Submit][Status][Discuss] Description 某人读论文,一篇论文是由许多单词组成.但他发现一个单词会在论文中出现很多次,现在想知道每个单词分别在论文中出现多少次. Input 第一个一个整数N,表示有多少个单词,接下来N行每行一个单词.每个单词由小写字母组成,N<=200,单词长度不超过10^6

题解 HDU 3698 Let the light guide us Dp + 线段树优化

http://acm.hdu.edu.cn/showproblem.php?pid=3698 Let the light guide us Time Limit: 5000/2000 MS (Java/Others)    Memory Limit: 62768/32768 K (Java/Others) Total Submission(s): 759    Accepted Submission(s): 253 Problem Description Plain of despair was

HDU 5172 GTY&#39;s gay friends (预处理+线段树)

题目链接:HDU 5172 GTY's gay friends 题意:给出一串序列,询问[l,r]区间里是否存在1~l-r+1的一个排列. 思路:1~l-r+1的一个排列 等价于 [l,r]中元素互不相同且[l,r]区间和等于(1+len)*len/2(len=l-r+1). 区间和可以用前缀和来处理. 元素互不相同,记录位置i上a[i]上次出现的位置记做pre[i],再用线段树来维护区间的pre最大值,若最大值小于l说明[l,r]中元素互不相同.(区间[l,r]中的每个pre[i]小于l说明区

hdu 1823 Luck and Love ,二维线段树

Luck and Love Time Limit: 10000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 5282    Accepted Submission(s): 1324 Input 本题有多个测试数据,第一个数字M,表示接下来有连续的M个操作,当M=0时处理中止. 接下来是一个操作符C. 当操作符为'I'时,表示有一个MM报名,后面接着一个整数,H表示身