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树上跑时经过的点在fail树上加1。然后每一个x的贡献就是x的子树和。这个我们在fail树上DP(合并size)再做一个前缀合就能做到\(O(n)\)预处理\(O(1)\)查询。复杂度\(O(nL)\)无法通过此题。
然后我们对询问分块。长度大于\(sqrt(L)\)的用方法二,其他的用方法一。这样方法二最多用\(\sqrt{n}\)次。复杂度\(O(\sqrt{n}L)\)。方法一因为么次询问的串长最多为\(\sqrt{L}\),所以复杂度为\(O(m\sqrt{L}logL)\)最终复杂度就是这两个加起来。可以通过此题。

#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<queue>
#include<vector>
using namespace std;
const int N=201000;
const int M=501000;
int cnt,head[N];
int n,m;
long long ans[M];
int dfn[N],R[N],L[N],tot,LEN;
long long tr[N];
long long size[N],sum[N];
string s[N];
struct ques{
    int x,k,id;
    ques(int xx=0,int kk=0,int idd=0){
        x=xx;k=kk;id=idd;
    }
};
vector<ques> vec1[N],vec2[N];
struct edge{
    int to,nxt;
}e[N];
void add_edge(int u,int v){
    cnt++;
    e[cnt].nxt=head[u];
    e[cnt].to=v;
    head[u]=cnt;
}
int lowbit(int x){
    return x&-x;
}
void add(int x,int w){
    for(int i=x;i<=tot;i+=lowbit(i))tr[i]+=w;
}
long long getsum(int x){
    long long tmp=0;
    for(int i=x;i;i-=lowbit(i))tmp+=tr[i];
    return tmp;
}
void dfs(int u){
    dfn[u]=++tot;
    for(int i=head[u];i;i=e[i].nxt){
        int v=e[i].to;
        dfs(v);
    }
    R[u]=tot;
}
void dfs1(int u){
    for(int i=head[u];i;i=e[i].nxt){
        int v=e[i].to;
        dfs1(v);
        size[u]+=size[v];
    }
}
struct AC{
    int point[N],trans[N][27],tot,fail[N];
    void ins(string s,int len,int k){
        int now=0;
        for(int i=0;i<len;i++){
            if(trans[now][s[i]-'a'+1]==0)trans[now][s[i]-'a'+1]=++tot;
            now=trans[now][s[i]-'a'+1];
        }
        point[k]=now;
    }
    void get_fail(){
        queue<int> q;
        for(int i=1;i<=26;i++)if(trans[0][i])q.push(trans[0][i]);
        while(!q.empty()){
            int now=q.front();
            q.pop();
            for(int i=1;i<=26;i++){
                if(trans[now][i])fail[trans[now][i]]=trans[fail[now]][i],q.push(trans[now][i]);
                else trans[now][i]=trans[fail[now]][i];
            }
        }
    }
}ac;
int read(){
    int sum=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){sum=sum*10+ch-'0';ch=getchar();}
    return sum*f;
}
int main(){
    n=read();m=read();
    for(int i=1;i<=n;i++){
        cin>>s[i];
        L[i]=s[i].size();
        LEN+=L[i];
        ac.ins(s[i],L[i],i);
    }
    int hhh=getchar();
    int block=sqrt(LEN);
    ac.get_fail();
    for(int i=1;i<=ac.tot;i++)add_edge(ac.fail[i],i);
    dfs(0);
    for(int i=1;i<=m;i++){
        int a=read(),b=read(),c=read();
        if(L[c]>block){
            vec1[c].push_back(ques(b,1,i)),vec1[c].push_back(ques(a-1,-1,i));
        }
        else vec2[a-1].push_back(ques(c,-1,i)),vec2[b].push_back(ques(c,1,i));
    }
    for(int i=1;i<=n;i++){
        int now=0;
        for(int j=0;j<L[i];j++){
            now=ac.trans[now][s[i][j]-'a'+1];
            if(j==L[i]-1)add(dfn[now],1),add(R[now]+1,-1);
        }
        for(int j=0;j<vec2[i].size();j++){
            int now=0;
            for(int k=0;k<L[vec2[i][j].x];k++){
                now=ac.trans[now][s[vec2[i][j].x][k]-'a'+1];
                ans[vec2[i][j].id]+=(long long)vec2[i][j].k*getsum(dfn[now]);
            }
        }
        if(vec1[i].size()){
            for(int j=0;j<=tot;j++)size[j]=sum[j]=0;
            int now=0;
            for(int j=0;j<L[i];j++)now=ac.trans[now][s[i][j]-'a'+1],size[now]++;
            dfs1(0);
            for(int j=1;j<=n;j++)sum[j]=sum[j-1]+size[ac.point[j]];
            for(int j=0;j<vec1[i].size();j++)
                ans[vec1[i][j].id]+=(long long)vec1[i][j].k*sum[vec1[i][j].x];
        }
    }
    for(int i=1;i<=m;i++)printf("%lld\n",ans[i]);
    return 0;
}

原文地址:https://www.cnblogs.com/Xu-daxia/p/10235862.html

时间: 2024-07-30 03:56:22

CF587F Duff is Mad(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 输入小写字母,打字机的一个凹槽中会加入这个字母(这个字母加在凹槽

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

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开始顺序编号,一直到

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

[ACM-ICPC 2018 沈阳网络赛] Ka Chang (dfs序+树状数组+分块)

Given a rooted tree ( the root is node 11 ) of NN nodes. Initially, each node has zero point. Then, you need to handle QQ operations. There're two types: 1\ L\ X1 L X: Increase points by XX of all nodes whose depth equals LL ( the depth of the root i

luogu SP8093 后缀自动机+树状数组+dfs序

这题解法很多,简单说几个: 1. 线段树合并,时间复杂度是 $O(nlog^2n)$ 的. 2. 暴力跳 $fail,$ 时间复杂度 $O(n\sqrt n),$ 比较暴力. 3. 建立后缀树后在 $dfs$ 序上数点,时间复杂度为 $O(nlogn),$ 十分优秀. Code: #include <bits/stdc++.h> #define N 200007 #define setIO(s) freopen(s".in","r",stdin) , f

【莫比乌斯反演+树状数组+分块求和】GCD Array

https://www.bnuoj.com/v3/contest_show.php?cid=9149#problem/I [题意] 给定长度为l的一个数组,初始值为0:规定了两种操作: [思路] 找到了一个讲解很清楚的博客http://www.cnblogs.com/flipped/p/HDU4947.html [Accepted] 1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #inc