题意

给定 \(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;
}

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

  1. 洛谷P2414 阿狸的打字机 [NOI2011] AC自动机+树状数组/线段树

    正解:AC自动机+树状数组/线段树 解题报告: 传送门! 这道题,首先想到暴力思路还是不难的,首先看到y有那么多个,菜鸡如我还不怎么会可持久化之类的,那就直接排个序什么的然后按顺序做就好,这样听说有7 ...

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

    [题意]阿狸喜欢收藏各种稀奇古怪的东西,最近他淘到一台老式的打字机.打字机上只有28个按键,分别印有26个小写英文字母和'B'.'P'两个字母. 经阿狸研究发现,这个打字机是这样工作的: l 输入小写 ...

  3. 51nod 麦克打电话(AC自动机+树状数组)

    SAM+线段树合并的裸题. 但我们讨论AC自动机的做法. 先建出AC自动机.考虑询问在[a,b]中出现的次数就是\([1,b]\)的出现次数-\([1,a-1]\)的出现次数.把询问离线.然后我们要求 ...

  4. Codeforces 587F - Duff is Mad(根号分治+AC 自动机+树状数组)

    题面传送门 第一眼看成了 CF547E-- 话说 CF587F 和 CF547E 出题人一样欸--还有另一道 AC 自动机的题 CF696D 也是这位名叫 PrinceOfPersia 的出题人出的- ...

  5. Codeforces 547E - Mike and Friends(AC 自动机+树状数组)

    题面传送门 好久每做过 AC 自动机的题了--做几个题回忆一下罢 AC 自动机能够解决多串匹配问题,注意是匹配,碰到前后缀的问题那多半不在 AC 自动机能解决的范围内. 在初学 AC 自动机的时候相信 ...

  6. BZOJ2434: [Noi2011]阿狸的打字机(AC自动机 树状数组)

    Time Limit: 10 Sec  Memory Limit: 256 MBSubmit: 4140  Solved: 2276[Submit][Status][Discuss] Descript ...

  7. BZOJ3881[Coci2015]Divljak——AC自动机+树状数组+LCA+dfs序+树链的并

    题目描述 Alice有n个字符串S_1,S_2...S_n,Bob有一个字符串集合T,一开始集合是空的. 接下来会发生q个操作,操作有两种形式: “1 P”,Bob往自己的集合里添加了一个字符串P. ...

  8. bzoj 2434 AC自动机+树状数组

    2434: [Noi2011]阿狸的打字机 Time Limit: 10 Sec  Memory Limit: 256 MBSubmit: 3493  Solved: 1909[Submit][Sta ...

  9. [NOI2011]阿狸的打字机 --- AC自动机 + 树状数组

    [NOI2011] 阿狸的打字机 题目描述: 阿狸喜欢收藏各种稀奇古怪的东西,最近他淘到一台老式的打字机. 打字机上只有28个按键,分别印有26个小写英文字母和'B'.'P'两个字母.经阿狸研究发现, ...

随机推荐

  1. DBUtils (30)

    DBUtils是java编程中的数据库操作实用工具,小巧简单实用. DBUtils封装了对JDBC的操作,简化了JDBC操作,可以少写代码. Dbutils三个核心功能介绍 一.  QueryRunn ...

  2. Android获取全局Context的方法

    Android获取全局Context的方法 Android--应用全局获取Context - 超宇的博客 - CSDN博客https://blog.csdn.net/chaoyu168/article ...

  3. navicat链接阿里云mysql报80070007: SSH Tunnel: Server does not support diffie-hellman-group1-sha1 for keyexchange

      http://www.jianshu.com/p/200572ed066c navicat 链接数据库 使用navicat 的ssh通道连接数据库回遇到权限问题 错误代码如下: 80070007: ...

  4. bzoj4448 情报传递

    题目链接 离线+树上主席树,主席树维护时间标记 注意查询时如果c<0要把c赋为0: #include<iostream> #include<cstdio> #includ ...

  5. .NET 常用ORM之Gentle.Net

    .Net常用的就是微软的EF框架和Nhibernate,这两个框架用的都比较多就不做详细介绍了,今天我们来看看Gentle.Net,Gentle.Net是一个开源的优秀O/R Mapping的对象持久 ...

  6. 【javascript】对原型对象、原型链的理解

    原型对象,原型链这些知识属于基础类知识.但是平时开发过程中也很少用到. 看网上的意思,原型链用于es5开发场景下的继承.es6有了类语法糖之后,就自带继承了. 通过理解,个人画了一张原型链解构的关系图 ...

  7. usb帧格式

    源: usb帧格式

  8. Oracle之现有表上建新表、操作符、字符函数

    #PLSQL技术培训15页PPT利用现有表创建表(百度) 说明:做新操作前要对旧表备份  具体百度 语法: create table <new_table_name> as select ...

  9. No module named scrapy 成功安装scrapy,却无法import的解决方法

    今天本来准备写一个Python的爬虫,然而使用pip安装了Scrapy之后,却无论如何也无法import,显示的结果总是ImportError: No module named Scrapy.网上查阅 ...

  10. Golang的值类型和引用类型的范围、存储区域、区别

    常见的值类型和引用类型分别有哪些? 值类型:基本数据类型 int 系列, float 系列, bool, string .数组和结构体struct,使用这些类型的变量直接指向存在内存中的值,值类型的变 ...