【BZOJ3413】匹配 离线+后缀树+树状数组
【BZOJ3413】匹配
Description
.jpg)
Input
第一行包含一个整数n(≤100000)。
第二行是长度为n的由0到9组成的字符串。
第三行是一个整数m。
接下来m≤5·10行,第i行是一个由0到9组成的字符串s,保证单行字符串长度小于等于10^5,所有字符串长度和小于等于3·10^6
Output
输出m行,第i行表示第si和S匹配所比较的次数。
Sample Input
1090901
4
87650
0901
109
090
Sample Output
10
3
4
题解:题目是问你截止到匹配之前,A串的每个位置与B串的LCP+1之和。这要利用到一个性质,两个后缀的lcp长度等于后缀树上两个点的lca的mx值。所以我们对A串的反串建立后缀自动机,得到后缀树,然后将B串放到后缀树中进行匹配(后缀树中匹配不同于后缀自动机中的匹配,实现比较复杂,方法也有很多,可以看代码)。如果没有成功匹配,则我们取最后一个成功匹配的节点,从这个点沿着到根的路径一路走上去跑一个树形DP即可。如果匹配成功,我们记录一下匹配成功的节点以及匹配位置,然后离线处理。我们将原串中的点一个一个加到后缀树中去,用树状数组维护DFS序得到子树和,处理询问时依旧跑类似于树形DP的东西即可。
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
typedef long long ll;
const int N=200010; int n,m,tot,last,cnt;
char S[N],T[N];
int ch[N][10],mx[N],pre[N],p1[N],p2[N],mn[N],pos[N],qos[N],len[N],s[N],L[N],R[N],son[N][10],siz[N];
vector<int> q[N];
vector<int>::iterator it;
int f[N];
ll ans[N];
inline int extend(int x)
{
int p=last,np=++tot; last=np;
mx[np]=mx[p]+1,siz[np]=1;
for(;p&&!ch[p][x];p=pre[p]) ch[p][x]=np;
if(!p) ch[1][x]=np,pre[np]=1;
else
{
int q=ch[p][x];
if(mx[q]==mx[p]+1) pre[np]=q;
else
{
int nq=++tot; mx[nq]=mx[p]+1,R[nq]=R[q]-(mx[q]-mx[p]-1);
pre[nq]=pre[q],pre[np]=pre[q]=nq;
memcpy(ch[nq],ch[q],sizeof(ch[q]));
for(;p&&ch[p][x]==q;p=pre[p]) ch[p][x]=nq;
}
}
return np;
}
void dfs(int x)
{
p1[x]=++p2[0];
for(int i=0,y;i<10;i++) if((y=son[x][i])) dfs(y),siz[x]+=siz[y],mn[x]=min(mn[x],mn[y]);
p2[x]=p2[0];
}
inline void updata(int x)
{
for(int i=x;i<=tot;i+=i&-i) s[i]++;
}
inline int query(int x)
{
int ret=0,i;
for(i=x;i;i-=i&-i) ret+=s[i];
return ret;
}
int main()
{
scanf("%d%s",&n,S);
int i,j,x,y;
memset(mn,0x3f,sizeof(mn));
tot=last=1;
for(i=n-1;i>=0;i--) pos[i]=extend(S[i]-'0'),mn[pos[i]]=i,R[pos[i]]=n-1;
for(i=2;i<=tot;i++) L[i]=R[i]-(mx[i]-mx[pre[i]])+1,son[pre[i]][S[L[i]]-'0']=i;
scanf("%d",&m);
dfs(1);
R[1]=-1;
for(i=1;i<=m;i++)
{
scanf("%s",T),len[i]=strlen(T);
for(x=1,j=y=0;j<len[i];j++)
{
if(y<=R[x])
{
if(S[y]==T[j]) y++;
else break;
}
else
{
if(son[x][T[j]-'0']) x=son[x][T[j]-'0'],y=L[x]+1;
else break;
}
}
qos[i]=x;
if(j<len[i])
{
if(x==1) ans[i]=n;
else
{
ans[i]=n+1ll*siz[x]*min(mx[x]-mx[pre[x]],y-L[x]);
for(x=pre[x];x!=1;x=pre[x]) ans[i]+=1ll*(mx[x]-mx[pre[x]])*siz[x];
}
}
else
{
ans[i]=len[i]+mn[x];
if(mn[x]) q[mn[x]-1].push_back(i);
}
}
for(i=0;i<n;i++)
{
updata(p1[pos[i]]);
for(it=q[i].begin();it!=q[i].end();it++)
{
for(j=pre[qos[*it]];j;j=pre[j]) ans[*it]+=1ll*(mx[j]-mx[pre[j]])*(query(p2[j])-query(p1[j]-1));
}
}
for(i=1;i<=m;i++) printf("%lld\n",ans[i]);
return 0;
}
【BZOJ3413】匹配 离线+后缀树+树状数组的更多相关文章
- BZOJ3413: 匹配(后缀自动机,Parent树,线段树合并)
Description Input 第一行包含一个整数n(≤100000). 第二行是长度为n的由0到9组成的字符串. 第三行是一个整数m. 接下来m≤5·10行,第i行是一个由0到9组成的字符串s, ...
- CodeForces -163E :e-Government (AC自动机+DFS序+树状数组)
The best programmers of Embezzland compete to develop a part of the project called "e-Governmen ...
- 【loj6041】「雅礼集训 2017 Day7」事情的相似度 后缀自动机+STL-set+启发式合并+离线+扫描线+树状数组
题目描述 给你一个长度为 $n$ 的01串,$m$ 次询问,每次询问给出 $l$ .$r$ ,求从 $[l,r]$ 中选出两个不同的前缀的最长公共后缀长度的最大值. $n,m\le 10^5$ 题解 ...
- BZOJ 2780 Sevenk Love Oimaster (后缀自动机+树状数组+dfs序+离线)
题目大意: 给你$n$个大串和$m$个询问,每次给出一个字符串$s$询问在多少个大串中出现过 好神的一道题 对$n$个大串建出广义$SAM$,建出$parent$树 把字符串$s$放到$SAM$里跑, ...
- Sereja and Brackets CodeForces - 380C (树状数组+离线)
Sereja and Brackets 题目链接: CodeForces - 380C Sereja has a bracket sequence s1, s2, ..., *s**n, or, in ...
- bzoj2743离线+树状数组
奇葩染色,对于每一个点关心的是前前个同颜色的位置,但是处理方法相同 离线比较神奇,按照右端点排序,然后每次用的是左端点,就不用建可持久化树状数组(什么鬼)了 区间修改+单点查询 果断差分以后用树状数组 ...
- BZOJ1878: [SDOI2009]HH的项链[树状数组 离线]
1878: [SDOI2009]HH的项链 Time Limit: 4 Sec Memory Limit: 64 MBSubmit: 3486 Solved: 1738[Submit][Statu ...
- HDU 4605 Magic Ball Game (dfs+离线树状数组)
题意:给你一颗有根树,它的孩子要么只有两个,要么没有,且每个点都有一个权值w. 接着给你一个权值为x的球,它从更节点开始向下掉,有三种情况 x=w[now]:停在此点 x<w[now]:当有孩子 ...
- HDU3333 Turing Tree 树状数组+离线处理
Turing Tree Time Limit: 6000/3000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total ...
随机推荐
- 关于float样式
在认识float样式之前务必要认识position:absolute position:absolute 功能是:当前节点脱离文档流,对于其兄弟节点(即同一父节点下的节点)已经感觉不到他的存在(即他的 ...
- python 类属性 、实例属性,可变数据结构作为类属性需要注意的地方
1.一些经典的python错误不去阅读和不重视,就会把错误的做法带入到实际项目中来,甚至造成难以排查问题. 2.有一个大笨猪,按java写观察者模式,java写得是直接在类名下声明一个实例属性(不加s ...
- SQL Compare数据库比较工具 完全破解+使用教程
来源http://www.cnblogs.com/duci/articles/4482665.html 一.使用教程 SQL Compare是编程人员常用的比较两个数据库之间差异的工具.可以用来比较数 ...
- 如何在O(n)的时间复杂度内找出数组中出现次数超过了一半的数
方法一:每次取出两个不同的数,剩下的数字中重复出现次数超过一半的数字肯定,将规模缩小化.如果每次删除两个不同的数,这里当然不是真的把它们踢出数组,而是对于候选数来说,出现次数减一,对于其他数来说,循环 ...
- PMP模拟考试-1
1. A manufacturing project has a schedule performance index (SPI) of 0.89 and a cost performance ind ...
- Hightchart 技巧
http://blog.csdn.net/u014796515/article/details/24428131
- PHP 使用 MongoDB
PHP 想要往 MongoDB 里增删查改数据,需要先安装 mongodb 或 mongo 扩展模块,一般两个都装上: cd /usr/local/src/ wget https://pecl.php ...
- 脚本控制animation的事件
由于动作设计经常修改动作,所以每次改完都要再添加一次animation的事件,所以就直接写了个脚本,当然以后可以做成表格,然后用脚本从表格中读取,然后生成对应的animation事件.在Assets/ ...
- 国内CDN加速现状
什么是CDN CDN的全称是Content Delivery Network,即内容分发网络.是位于网络层与应用层之间的网络应用,其目的是通过在现有的Internet中增加一层新的网络架构,将网站的内 ...
- Windows下mysql重设密码
Windows下的实际操作如下 .关闭正在运行的MySQL,即关闭服务. .打开DOS窗口,转到mysql\bin目录. .输入 mysqld --skip-grant-tables 回车.如果没有出 ...