[gym104542F] Interesting String Problem
Since you are a good friend of Jaber and Eyad, they are asking for your help to solve this problem.
You are given a graph consisting of \(n\) nodes, which initially has no edges. For each node \(i\),there's a string \(s_i\)
of lowercase Latin letters written on it.
You have to process \(q\) queries of two types:
- 1 \(u\) \(v\) : it means add an edge between node uand node v.
- 2 \(u\) \(t\) : it means for node \(u\) and string \(t\), output the sum of \(cnt_v\) over all nodes \(v\) which belong to the same component as \(u\),where \(cnt_v\) is the number of times \(s_v\) occurs in \(t\) as a substring.
It is guaranteed that the sum of lengths of sv doesn't exceed \(5\times10^5\), and sum of lengths of the query strings doesn't exceed \(5\times10^5\)
1 二进制分组
合并的时候,AC 自动机很难合并,所以考虑定期重构。
对每个点开一个栈,分别表示 \(2^i\) 个串的合并。加入栈时,如果同时存在两个有 \(2^i\) 个串的时候就把他重构成一个 \(2^{i+1}\) 的串。观察到每个串都会被重构 \(\log n\) 次,算上重构,复杂度就 \(O(|S_i|log n|\Sigma|)\)
2.线段树合并。
由于一开始就把所有的串给了出来,所以可以直接给他跑一个 AC 自动机,弄出fail 树。
考虑我后面的询问需要知道什么,需要知道这个点在 fail 树上有多少个祖先是和 \(x\) 在同一个连通块里面的。所以可以用线段树合并去维护这个东西。在第 \(x\) 棵线段树上把 \(dfn_x,dfn_x+sz_x-1\) 这段区间赋值成 \(1\),然后进行线段树合并,单点查询就可以得到答案了。
#include<bits/stdc++.h>
using namespace std;
const int N=5e5+5,M=2e5+5;;
int idx,tr[N][26],tme=-1,hd[N],dfn[N],sz[N],u,v,fa[N],op,n,fil[N],q[N],l,r,e_num;
long long ans;
char str[N];
struct edge{
int v,nxt;
}e[N<<1];
string s[M];
void add_edge(int u,int v)
{
e[++e_num]=(edge){v,hd[u]};
hd[u]=e_num;
}
int read()
{
int s=0;
char ch=getchar();
while(ch<'0'||ch>'9')
ch=getchar();
while(ch>='0'&&ch<='9')
s=s*10+ch-48,ch=getchar();
return s;
}
struct segment{
int rt[M],tr[N*30],lc[N*30],rc[N*30],idx;
int merge(int u,int v)
{
if(!u||!v)
return u|v;
tr[u]+=tr[v];
lc[u]=merge(lc[u],lc[v]);
rc[u]=merge(rc[u],rc[v]);
return u;
}
void upd(int&o,int l,int r,int x,int y)
{
if(!o)
o=++idx;
if(x<=l&&r<=y)
{
tr[o]++;
return;
}
int md=l+r>>1;
if(md>=x)
upd(lc[o],l,md,x,y);
if(md<y)
upd(rc[o],md+1,r,x,y);
}
int qry(int&o,int l,int r,int x)
{
if(!o)
return 0;
if(l==r)
return tr[o];
int md=l+r>>1;
if(md>=x)
return qry(lc[o],l,md,x)+tr[o];
return qry(rc[o],md+1,r,x)+tr[o];
}
void mge(int x,int y)
{
rt[y]=merge(rt[y],rt[x]);
}
}b;
void insert(string s,int x)
{
int u=0;
for(int i=0;i<s.size();i++)
{
if(!tr[u][s[i]-'a'])
tr[u][s[i]-'a']=++idx;
u=tr[u][s[i]-'a'];
}
}
void build()
{
l=1,r=0;
for(int i=0;i<26;i++)
if(tr[0][i])
q[++r]=tr[0][i];
while(l<=r)
{
for(int i=0;i<26;i++)
{
if(tr[q[l]][i])
fil[q[++r]=tr[q[l]][i]]=tr[fil[q[l]]][i];
else
tr[q[l]][i]=tr[fil[q[l]]][i];
}
++l;
}
for(int i=1;i<=idx;i++)
add_edge(fil[i],i);
}
void sou(int x)
{
dfn[x]=++tme,sz[x]=1;
for(int i=hd[x];i;i=e[i].nxt)
sou(e[i].v),sz[x]+=sz[e[i].v];
}
int find(int x)
{
if(fa[x]==x)
return x;
return fa[x]=find(fa[x]);
}
int main()
{
n=read();
for(int i=1;i<=n;i++)
scanf("%s",str),insert(s[i]=str,fa[i]=i);
build();
sou(0);
for(int i=1;i<=n;i++)
{
int u=0;
for(int j=0;j<s[i].size();j++)
u=tr[u][s[i][j]-'a'];
b.upd(b.rt[i],0,idx,dfn[u],dfn[u]+sz[u]-1);
}
int q=read();
while(q--)
{
op=read();
if(op==1)
{
u=read(),v=read();
if(find(u)^find(v))
{
b.mge(find(u),find(v));
fa[find(u)]=find(v);
}
}
else
{
ans=0;
u=read(),scanf("%s",str);
u=find(u);
int k=0;
for(int i=0;str[i];i++)
{
k=tr[k][str[i]-'a'];
ans+=b.qry(b.rt[u],0,idx,dfn[k]);
}
printf("%lld\n",ans);
}
}
}
- Kruskal重构树。
给询问他建一个 kruskal 重构树,然后一次询问在 kruskal 重构树上是一段连续区间 \([l,r]\) 的询问,可以拆成 \(l-1\) 和 \(r\) 的询问,不断给线段树中加入元素,回答询问即可。
[gym104542F] Interesting String Problem的更多相关文章
- FZU - 2218 Simple String Problem(状压dp)
Simple String Problem Recently, you have found your interest in string theory. Here is an interestin ...
- hdu String Problem(最小表示法入门题)
hdu 3374 String Problem 最小表示法 view code#include <iostream> #include <cstdio> #include &l ...
- HDU 3374 String Problem(KMP+最大/最小表示)
String Problem Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) T ...
- 【HDU3374】 String Problem (最小最大表示法+KMP)
String Problem Description Give you a string with length N, you can generate N strings by left shift ...
- HDOJ3374 String Problem 【KMP】+【最小表示法】
String Problem Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) T ...
- HDU 3374 String Problem (KMP+最大最小表示)
HDU 3374 String Problem (KMP+最大最小表示) String Problem Time Limit: 2000/1000 MS (Java/Others) Memory ...
- String Problem hdu 3374 最小表示法加KMP的next数组
String Problem Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)To ...
- ACM-ICPC2018南京赛区 Mediocre String Problem
Mediocre String Problem 题解: 很容易想到将第一个串反过来,然后对于s串的每个位置可以求出t的前缀和它匹配了多少个(EXKMP 或者 二分+hash). 然后剩下的就是要处理以 ...
- hdu3374 String Problem【最小表示法】【exKMP】
String Problem Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)To ...
- hdu 5772 String problem 最大权闭合子图
String problem 题目连接: http://acm.hdu.edu.cn/showproblem.php?pid=5772 Description This is a simple pro ...
随机推荐
- 应用管理平台Walrus开源,构建软件交付新范式
今日,数澈软件Seal(以下简称"Seal")宣布正式开源 Walrus,这是一款基于平台工程理念的应用管理平台,致力于解决应用交付领域的深切痛点. 借助 Walrus 将云原生的 ...
- 二叉搜索树(Binary Search Tree,BST)
二叉搜索树(Binary Search Tree,BST) 二叉搜索树(Binary Search Tree),也称二叉查找树或二叉排序树,是一种特殊的二叉树,它满足以下性质 对于二叉搜索树的每个节点 ...
- Lua5.3 笔记
Lua5.3 笔记 最近用skynet,sproto通讯,完全看不懂通讯二进制是怎么写的,发现都是string这个,string那个,完全理解不来. 于是查了一下string.pack的api,和之前 ...
- Github、Gitee优秀的开源项目
收集 Github.Gitee优秀的开源项目,并进行归类整理.项目地址 目录 编程语言项目 SprinBoot 项目 源码分析项目 前后端分离项目 Vue2 项目 Vue3 项目 微服务项目 Api ...
- Note -「Suffix Automaton」SAM
Part. 1 基本信息 Part. 1-1 SAM 的构成. SAM 由两个东西构成,一个是一个 DAWG,还有一棵外向树,叫 parent tree. 比如,给你一个字符串 \(S=\sf abb ...
- 编译nw-node版本的插件
编译nw-node版本的插件 下载nwjs对应版本的nodejs 原始源码目录 yh@yh:~/addon$ tree . ├── addon.cc ├── binding.gyp ├── CppLi ...
- SQL连接符Left Join小实例
在一数据移植项目中,Left Join的应用 项目要求根据卡号获取最终用户号,规则如下: 1.根据card查询tbl_TestA表,获取userid,根据userid作为id查询tbl_TestB获 ...
- Xshell远程连接、MBR/BOOT和GRUB三者关系总结(系统启动过程)
远程连接 远程连接Linux服务器的常见工具有Xshell.SecureCRT.Putty等,这些客户端连接工具在Linux服务器对应着相同SSH服务进程sshd,即远程连接都是使用SSH协议,当然它 ...
- ios ipa apple company 开发者账号申请分享攻略
ios公司开发者账号申请分享攻略 好不容易终于申请下来了ios 公司开发者账号,真是一路艰辛和漫长啊,特别是对于远在大洋彼岸的大中华国家.以下我就分享一下这一路下来的经验,希望对于那些新手同仁们有所帮 ...
- 获取 + 查看 Android 源码的 方法
Android源码获取方法. 作为一个Android开发者,必要的时候阅读以下源码可以拓宽一下自己的视野和对android的认知程度. Google的Android的源码管理仓库是用的是Git.And ...