正题

题目链接:https://www.luogu.com.cn/problem/CF587F


题目大意

给出nnn个字符串sss。qqq次询问给出l,r,kl,r,kl,r,k要求输出sl..rs_{l..r}sl..r​在sks_ksk​中出现了多少次。

1≤n,q,∑∣si∣≤1051\leq n,q,\sum |s_i|\leq 10^51≤n,q,∑∣si​∣≤105


解题思路

考虑一个比较暴力的做法,先把所有的构出一棵ACACAC自动机,一个串SSS有后缀TTT当且仅当在failfailfail树上SSS的节点在TTT的子树内。

所以暴力的做法就是统计sks_ksk​的节点有多少在sl..rs_{l..r}sl..r​的终止节点子树内的节点。

需要优化,因为有L=∑∣si∣≤105L=\sum |s_i|\leq 10^5L=∑∣si​∣≤105,所以可以考虑根号分治,设定值T=LT=\sqrt{L}T=L​。

对于长度大于TTT的kkk,我们所有的询问统一差分变为前缀问题处理。因为这样的串的个数不会超过L\sqrt LL​个,所以可以每次暴力O(n)O(n)O(n)处理。

我们把所有sks_ksk​路径上的节点权值加一,然后暴力扫描nnn个串,每次终止节点统计子树内的权值和。

对于长度小于等于TTT的kkk,我们差分后按照询问端点排序,从左到右扫过nnn个串每次子树内的权值加一,然后每次暴力扫描sks_ksk​的所有节点统计权值就好了。
使用树状数组时间复杂度O(nnlog⁡n)O(n\sqrt n\log n)O(nn​logn),已经可以通过本题了。但是如果把树状数组改成分块就可以平衡到O(nn)O(n\sqrt n)O(nn​),但是我懒


code

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
#include<queue>
#include<cmath>
#define ll long long
#define mp(x,y) make_pair(x,y)
#define lowbit(x) (x&-x)
using namespace std;
const ll N=1e5+10;
struct node{ll to,next;
}a[N];
ll n,m,T,tot,dfr,L,top[N],ls[N],l[N],t[N],ans[N];
ll cnt,ch[N][26],fail[N],pos[N],rfn[N],ed[N];
vector<pair<ll,ll> > v[N],V[N];
char *s[N],st[N];queue<ll> q;
void Change(ll x,ll val){while(x<=dfr){t[x]+=val;x+=lowbit(x);}return;
}
ll Ask(ll x){ll ans=0;while(x){ans+=t[x];x-=lowbit(x);}return ans;
}
void addl(ll x,ll y){a[++tot].to=y;a[tot].next=ls[x];ls[x]=tot;return;
}
ll Insert(char *s,ll l){ll x=0;for(ll i=0;i<l;i++){ll c=s[i]-'a';if(!ch[x][c])ch[x][c]=++cnt;x=ch[x][c];}return x;
}
void GetFail(){for(ll i=0;i<26;i++)if(ch[0][i])q.push(ch[0][i]);while(!q.empty()){ll x=q.front();q.pop();for(ll i=0;i<26;i++){if(!ch[x][i])ch[x][i]=ch[fail[x]][i];else{fail[ch[x][i]]=ch[fail[x]][i];q.push(ch[x][i]);}}}for(ll i=1;i<=cnt;i++)addl(fail[i],i);return;
}
void dfs(ll x,ll fa){rfn[x]=++dfr;for(ll i=ls[x];i;i=a[i].next){ll y=a[i].to;if(y==fa)continue;dfs(y,x);}ed[x]=dfr;return;
}
signed main()
{scanf("%lld%lld",&n,&m);for(ll i=1;i<=n;i++){s[i]=st+top[i];scanf("%s",s[i]);l[i]=strlen(s[i]);top[i+1]=top[i]+l[i];pos[i]=Insert(s[i],l[i]);}L=top[n+1];T=sqrt(L);GetFail();dfs(0,0);for(ll i=1;i<=m;i++){ll L,R,K;scanf("%lld%lld%lld",&L,&R,&K);if(l[K]<=T)v[R].push_back(mp(K,i)),v[L-1].push_back(mp(K,-i));else V[K].push_back(mp(R,i)),V[K].push_back(mp(L-1,-i));}for(ll p=1;p<=n;p++)if(l[p]>T){memset(t,0,sizeof(t));sort(V[p].begin(),V[p].end());ll x=0;for(ll i=0;i<l[p];i++){x=ch[x][s[p][i]-'a'];Change(rfn[x],1);}ll z=0,sum=0;while(z<V[p].size()&&!V[p][z].first)z++;for(ll i=1;i<=n;i++){sum+=Ask(ed[pos[i]])-Ask(rfn[pos[i]]-1);while(z<V[p].size()&&V[p][z].first<=i){ll id=V[p][z].second,op=1;if(id<0)id=-id,op=-op;ans[id]+=sum*op;z++;}}}memset(t,0,sizeof(t));for(ll p=1;p<=n;p++){Change(rfn[pos[p]],1);Change(ed[pos[p]]+1,-1);for(ll i=0;i<v[p].size();i++){ll k=v[p][i].first,id=v[p][i].second,op=1;if(id<0)id=-id,op=-op;ll x=0;for(ll j=0;j<l[k];j++){x=ch[x][s[k][j]-'a'];ans[id]+=op*Ask(rfn[x]);}}}for(ll i=1;i<=m;i++)printf("%lld\n",ans[i]);return 0;
}

CF587F-Duff is Mad【AC自动机,根号分治】相关推荐

  1. [CF587F]Duff is Mad[AC自动机+根号分治+分块]

    题意 给你 \(n\) 个串 \(s_{1\cdots n}\) ,每次询问给出 \(l,r,k\) ,问在 \(s_{l\cdots r}\) 中出现了多少次 \(s_k\) . \(n,q,\su ...

  2. CF587F Duff is Mad

    题目描述 题解: 有个$O(\sum 询问k串长)$的做法就不说了. 当然是过不去的. 貌似第22个点总长1e5只有三个串 所以考虑对询问的$k$串串长分开算. 先建$fail$树. 对于$s_k&g ...

  3. NOI.AC#2266-Bacteria【根号分治,倍增】

    正题 题目链接:http://noi.ac/problem/2266 题目大意 给出nnn个点的一棵树,有一些边上有中转站(边长度为222,中间有一个中转站),否则就是边长为111. mmm次询问一个 ...

  4. [XSY3320] string (AC自动机,哈希,点分治)

    XSY3320 前置芝士:回文前缀&&borderborderborder 推荐博客 推荐博客 考虑点分治,问题变成求经过重心的回文路径个数. 一条经过重心的回文路径长这样: xxx到 ...

  5. [CTSC2010]珠宝商(点分治+根号分治+后缀自动机)

    [CTSC2010]珠宝商 洛谷题目传送门 简要题意 给定一颗nnn个节点的树,和一个长度为mmm的模式串SSS 树上每个节点都有一个字符 求树上所有路径的点的字符拼成的字符串在SSS中的出现次数之和 ...

  6. 【LOJ6681】yww 与树上的回文串(点分治)(AC自动机)(字符串哈希)(回文串broder理论)

    传送门 社论(题解): 首先长剖重剖都考虑过了,并没有办法支持快速合并,边分更不用说了,权值在边上怎么边分怎么蛋疼. 考虑点分,我们知道如果一个回文串过了重心,他要么就是重心延伸出去的回文前缀,要么它 ...

  7. 【CTSC2010】珠宝商【后缀自动机】【点分治】【根号分治】

    题意:给一棵 nnn 个点的树,每个点有个字符,另给一个长度为 mmm 的特征串,求树上 n2n^2n2 条有向路径在特征串中出现的次数之和. n,m≤5×104n,m\leq 5\times 10^ ...

  8. 树链剖分 or 根号分治 + dfs序 + 树状数组 ---- CF1254 D. Tree Queries

    题目链接 题目大意: 问题转化: 很容易发现:假设修改的节点是vvv. 1.vvv的子树sonvson_vsonv​直接加上(n−size[sonv])n×d\frac{(n-size[son_v]) ...

  9. Codeforces Round #507 (Div. 1) D. You Are Given a Tree 根号分治 + dp

    传送门 题意: 有一颗nnn个节点的树,其中一个简单路径集合被称为kkk合法当且仅当: 树的每个节点至多属于一条路径,且每条路径恰好包含kkk个点. 对于k∈[1,n]k\in [1,n]k∈[1,n ...

最新文章

  1. 使用神经网络摸你加法器
  2. SQLServer “无法对数据库‘XXX‘ 执行删除,因为它正用于复制”的解决方法
  3. MySQL高级 - 锁 - MyISAM表锁 - 查看锁争用情况
  4. 基于android公交车线路查询论文文献,本科毕业论文---基于android的手机公交线路查询系统.doc...
  5. 漫步凸分析五——函数运算
  6. 【IDEA】IDEA 下 如何 jstack 线程状态
  7. Mathematical operation
  8. python做服务器需要什么模块_用Python自带的包建立简单的web服务器
  9. 并发学习之CyclicBarrier循环栅栏
  10. python初学第一节课
  11. 英语中学生测试软件,初中生免费学英语的软件哪个好
  12. 软考网工-第四章知识产权与标准化
  13. 史上最全的疫情历史数据
  14. 少年,暑期学编程可好?
  15. linux下的go富集分析,GO富集分析
  16. Linux使用vi修改、删除、保存文件
  17. zepto - 实现滑动翻页
  18. 《面朝大海,春暖花开》(海子)
  19. 软件测试——基础篇(软件测试的生命周期和BUG的概念)
  20. 红外通信的应用——PPM调制与解码(C51)

热门文章

  1. python解析xml文件选用模块_python解析xml模块封装代码
  2. laravel缓存html,Laravel 静态页面缓存 JosephSilber/page-cache - 码农天地
  3. shiro单点登录原理_SSO单点登录三种情况的实现方式详解
  4. 各纬度气候分布图_欧洲气候特征:以温带气候类型为主,是海洋性气候最显著的大洲...
  5. 实现option上下移动_用jQuery实现lt;selectgt;选项上下移动 - 不要哀求 学会争取 若是如此 终有所获 - ITeye博客...
  6. 鸿蒙系统可以替代安卓吗,华为今天发布的鸿蒙系统,到底能不能替代安卓?
  7. idea中右侧的Maven框消失了
  8. 万字总结webpack实战案例配置
  9. [JavaWeb-XML]XML基本语法与快速入门
  10. [Java基础]Stream流终结操作之forEachcount