HDU 6096 String(AC自动机+树状数组)

题意

给定 \(n\) 个单词,\(q\) 个询问,每个询问包含两个串 \(s_1,s_2\),询问有多少个单词以 \(s_1\) 为前缀, \(s_2\) 为后缀,前后缀不能重叠。

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

思路

字符串题有一个小技巧,拼接字符串,中间加上连接符。如这道题,可以将查询变成 \(s_2+\text{\{}+s_1\) 的形式,相应的,把单词 \(T\) 变为 \(T+\text{\{}+T\) 的形式。那么就是普通的匹配问题了。

对于询问建立\(\text{AC}\)自动机。同样发现一个匹配指针遍历到节点 \(u\) 时,\(u\) 在 \(fail\) 树上的父节点也得配。但这道题,直接树上差分并未考虑前后缀不能重叠的约束条件。不难发现,我们只要先将更新和查询按照长度从大到小进行归并就可以解决这个问题,直接把树上差分改成在线的树状数组维护 \(\text{dfs}\) 序即可。

代码

#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)
typedef long long LL;
using namespace std;
const int N=1e5+5;
const int M=5e5+5;
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));}
    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 FenwickTree
{
    #define lowbit(x) ((x)&-(x))
    int c[M*2],n;
    void build(int _n){n=_n;memset(c,0,sizeof(c));}
    void update(int k,int val){for(;k<=n;k+=lowbit(k))c[k]+=val;}
    int query(int k){int res=0;for(;k>0;k^=lowbit(k))res+=c[k];return res;}
    int query(int l,int r){return query(r)-query(l-1);}
    #undef lowbit
};
Linked_list<M*2,M*2>G;
FenwickTree FT;
int ch[M*2][27],f[M*2];
int rt,tot;
int L[M*2],R[M*2],ord;
string P[N],T[N],s1,s2;
int Plen[N],Tlen[N];
int p[N],t[N];
int Output[N];
int n,q;

bool cmp_T(int x,int y){return Tlen[x]>Tlen[y];}
bool cmp_P(int x,int y){return Plen[x]>Plen[y];}
void build(){rt=tot=0;}
void create(int &k)
{
    if(!k)
    {
        k=++tot;
        FOR(i,0,26)ch[k][i]=0;
    }
}
void insert(int &k,string &str)
{
    create(k);
    int now=k;
    FOR(i,0,str.length()-1)
    {
        create(ch[now][str[i]-'a']);
        now=ch[now][str[i]-'a'];
    }
}
void get_fail()
{
    queue<int>Q;
    while(!Q.empty())Q.pop();
    f[rt]=rt;
    FOR(i,0,26)
    {
        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,26)
        {
            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 update(string &str)
{
    int now=rt;
    FOR(i,0,(int)str.length()-1)
    {
        now=ch[now][str[i]-'a'];
        FT.update(L[now],1);
    }
}
int query(string &str)
{
    int now=rt;
    FOR(i,0,(int)str.length()-1)
        now=ch[now][str[i]-'a'];
    return FT.query(L[now],R[now]);
}

int main()
{
    int Case;
    scanf("%d",&Case);
    while(Case--)
    {
        build();
        scanf("%d%d",&n,&q);
        FOR(i,1,n)
        {
            cin>>s1;
            Tlen[i]=s1.length();
            T[i]=s1+'{'+s1;
        }
        FOR(i,1,q)
        {
            cin>>s1>>s2;
            Plen[i]=s1.length()+s2.length();
            P[i]=s2+'{'+s1;
        }

        FOR(i,1,q)insert(rt,P[i]);
        G.clear();FT.build(tot);
        get_fail();
        FOR(i,1,tot)if(f[i]!=i)G.add(f[i],i);
        ord=0;dfs_fail(rt);

        FOR(i,1,n)t[i]=i;
        FOR(i,1,q)p[i]=i;
        sort(t+1,t+1+n,cmp_T);
        sort(p+1,p+1+q,cmp_P);

        int upd=1;
        FOR(qry,1,q)
        {
            while(upd<=n&&Tlen[t[upd]]>=Plen[p[qry]])
                update(T[t[upd]]),upd++;
            Output[p[qry]]=query(P[p[qry]]);
        }

        FOR(i,1,q)printf("%d\n",Output[i]);
    }
    return 0;
}

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

时间: 2024-10-18 13:03:08

HDU 6096 String(AC自动机+树状数组)的相关文章

【BZOJ】2434: [Noi2011]阿狸的打字机 AC自动机+树状数组+DFS序

[题意]阿狸喜欢收藏各种稀奇古怪的东西,最近他淘到一台老式的打字机.打字机上只有28个按键,分别印有26个小写英文字母和'B'.'P'两个字母. 经阿狸研究发现,这个打字机是这样工作的: l 输入小写字母,打字机的一个凹槽中会加入这个字母(这个字母加在凹槽的最后). l 按一下印有'B'的按键,打字机凹槽中最后一个字母会消失. l 按一下印有'P'的按键,打字机会在纸上打印出凹槽中现有的所有字母并换行,但凹槽中的字母不会消失. 我们把纸上打印出来的字符串从1开始顺序编号,一直到n.打字机有一个非

bzoj 2434 AC自动机+树状数组

2434: [Noi2011]阿狸的打字机 Time Limit: 10 Sec  Memory Limit: 256 MBSubmit: 3493  Solved: 1909[Submit][Status][Discuss] Description 阿狸喜欢收藏各种稀奇古怪的东西,最近他淘到一台老式的打字机.打字机上只有28个按键,分别印有26个小写英文字母和'B'.'P'两个字母. 经阿狸研究发现,这个打字机是这样工作的: l 输入小写字母,打字机的一个凹槽中会加入这个字母(这个字母加在凹槽

CF587F Duff is Mad(AC自动机+树状数组+分块)

考虑两一个暴力 1 因为询问\([a,b]\)可以拆成\([1,b]\)-\([1,a-1]\)所以把询问离线,然后就是求\([1,x]\)中被\(S_i\)包含的串的数量.考虑当\([1,x-1]->[1,x]\)时我们把\(S_x\)结束节点在fail树的子树加1.然后询问就是求\(S_i\)在AC自动机上跑时经过所有点的点权用树状数组维护.设\(\sum{len[S_i]}=L\)这样的复杂度就是\(O(mLlogL)\)无法通过此题. 2 依然离线.这次我们把\(S_i\)放在fail树

CoderForces 163E e-Government(AC自动机+树状数组维护fail树的dfs序)

E. e-Government time limit per test 1 second memory limit per test 256 megabytes input standard input output standard output The best programmers of Embezzland compete to develop a part of the project called "e-Government" — the system of automa

BZOJ2434 NOI2011 阿狸的打字机 AC自动机+树状数组+DFS序

题意:给定三个操作:1.在当前字符串的末尾添加一个字符c  2.在当前字符串的末尾删除一个字符  3.记录当前字符串并对其标号.再给出N组询问,每组询问需回答第x个字符串在第y个字符串中出现的次数 题解: 首先按照如下规则建Trie,设当前节点为t,第i个字符串的结尾在Trie中的位置为mark[i]: 1.插入操作:看t是否有c这个儿子,有则t=t->child[c],否则t->child[c]=NewNode,t=t->child[c] 2.删除操作:t=t->father 3

[BZOJ 2434][Noi2011]阿狸的打字机(AC自动机+树状数组+dfs序)

Description 打字机上只有28个按键,分别印有26个小写英文字母和'B'.'P'两个字母.经阿狸研究发现,这个打字机是这样工作的: ·输入小写字母,打字机的一个凹槽中会加入这个字母(这个字母加在凹槽的最后). ·按一下印有'B'的按键,打字机凹槽中最后一个字母会消失. ·按一下印有'P'的按键,打字机会在纸上打印出凹槽中现有的所有字母并换行,但凹槽中的字母不会消失. 例如,阿狸输入aPaPBbP,纸上被打印的字符如下: a aa ab 我们把纸上打印出来的字符串从1开始顺序编号,一直到

HDU 6096 String (AC自动机)

题意:给出n个字符串和q个询问,每次询问给出两个串 p 和 s .要求统计所有字符串中前缀为 p 且后缀为 s (不可重叠)的字符串的数量. 析:真是觉得没有思路啊,看了官方题解,真是好复杂. 假设原始的字符串 数组为A,首先将A中的每个字符串都进行翻转,得到字符串数组B,然后,将A和B按字典序排序. 对于一个查询来说有一个前缀p和后缀s, 所有包含前缀p的字符串在A中是连续的,可通过二分求出该区间 设为[Lp,Rp],同样,所有包含后缀s的字符串在B中也是连续的,设为[Ls,Rs] 接下来只需

2017多校第6场 HDU 6096 String AC自动机

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6096 题意:给了一些模式串,然后再给出一些文本串的不想交的前后缀,问文本串在模式串的出现次数. 解法: 因为要求前缀后缀都包含的个数,所以可以把字符串a转换成a#a这样一个字符串,比如abca就转换成abca#abca 然后对于一组前缀a后缀b转换成b{a,比如ab ca,就是ca{ab, 然后对前缀后缀的串建立AC自动机,让主串去匹配,如上述例子,ca{ab满足为abca{abca的一个子串,也就

hdu 3015 Disharmony Trees (离散化+树状数组)

Disharmony Trees Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 663    Accepted Submission(s): 307 Problem Description One day Sophia finds a very big square. There are n trees in the square. T