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);
}
}
}
  1. Kruskal重构树。

给询问他建一个 kruskal 重构树,然后一次询问在 kruskal 重构树上是一段连续区间 \([l,r]\) 的询问,可以拆成 \(l-1\) 和 \(r\) 的询问,不断给线段树中加入元素,回答询问即可。

[gym104542F] Interesting String Problem的更多相关文章

  1. FZU - 2218 Simple String Problem(状压dp)

    Simple String Problem Recently, you have found your interest in string theory. Here is an interestin ...

  2. hdu String Problem(最小表示法入门题)

    hdu 3374 String Problem 最小表示法 view code#include <iostream> #include <cstdio> #include &l ...

  3. HDU 3374 String Problem(KMP+最大/最小表示)

    String Problem Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) T ...

  4. 【HDU3374】 String Problem (最小最大表示法+KMP)

    String Problem Description Give you a string with length N, you can generate N strings by left shift ...

  5. HDOJ3374 String Problem 【KMP】+【最小表示法】

    String Problem Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) T ...

  6. HDU 3374 String Problem (KMP+最大最小表示)

    HDU 3374 String Problem (KMP+最大最小表示) String Problem Time Limit: 2000/1000 MS (Java/Others)    Memory ...

  7. String Problem hdu 3374 最小表示法加KMP的next数组

    String Problem Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)To ...

  8. ACM-ICPC2018南京赛区 Mediocre String Problem

    Mediocre String Problem 题解: 很容易想到将第一个串反过来,然后对于s串的每个位置可以求出t的前缀和它匹配了多少个(EXKMP 或者 二分+hash). 然后剩下的就是要处理以 ...

  9. hdu3374 String Problem【最小表示法】【exKMP】

    String Problem Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)To ...

  10. hdu 5772 String problem 最大权闭合子图

    String problem 题目连接: http://acm.hdu.edu.cn/showproblem.php?pid=5772 Description This is a simple pro ...

随机推荐

  1. 不关闭Tamper Protection(篡改保护)下强制卸载Windows Defender和安全中心所有组件

    个人博客: xzajyjs.cn 背景介绍 由于微软不再更新arm版本的win10系统,因此只能通过安装insider preview的镜像来使用.而能找到的win10 on arm最新版镜像在安装之 ...

  2. Unity 性能优化之Shader分析处理函数ShaderUtil.HasProceduralInstancing: 深入解析与实用案例

    Unity 性能优化之Shader分析处理函数ShaderUtil.HasProceduralInstancing: 深入解析与实用案例 点击封面跳转到Unity国际版下载页面 简介 在Unity中, ...

  3. 【WPF】后台代码实现绑定ComboBox的SelectedItem功能

    WPF 开发程序目前最好的用的设计模式为MVVM模式,实现了前后端的分离,前端页面的更改不需要后台代码逻辑发生变化,同理,后台逻辑发生变化时基本上也不需要修改前台的页面布局等信息. 由于某些原因,可能 ...

  4. Note -「Polynomial」

    Part. 1 FFT Part. 1-1 Main 对于一个 \(n\) 次多项式 \(F(x)=\sum_{i=0}^{n}a_{i}x^{i}\),在平面直角坐标系中可以由 \(n+1\) 个点 ...

  5. 【Python爬虫】使用代理ip进行网站爬取

    使用代理IP进行网站爬取可以有效地隐藏你的真实IP地址,让网站难以追踪你的访问行为.本文将介绍Python如何使用代理IP进行网站爬取的实现,包括代理IP的获取.代理IP的验证.以及如何把代理IP应用 ...

  6. strcpy()函数详解

    strcpy()函数是C语言中的一个复制字符串的库函数,以下将详细解释说明一下: · 函数声明以及实现代码 char *strcpy(char *dst, const char *src);char ...

  7. Langchain-Chatchat项目:1-整体介绍

      基于Langchain与ChatGLM等语言模型的本地知识库问答应用实现.项目中默认LLM模型改为THUDM/chatglm2-6b[2],默认Embedding模型改为moka-ai/m3e-b ...

  8. LUSH & LUXURIOUS

    明亮色系Punchy & Bright 明亮.有着强烈对比的颜色更引人注目. 这种大胆的色彩组合要谨慎地利用,所以在明亮色系中的调和色一般用中性色. 其中不同的色彩饱和度,表现出不同的氛围和意 ...

  9. Go字符串实战操作大全!

    在本篇文章中,我们深入探讨了Go语言中字符串的魅力和深度.从基础定义.操作.字符编码到复杂的类型转换,每个环节都带有实例和代码示例来深化理解.通过这些深入的解析,读者不仅能够掌握字符串在Go中的核心概 ...

  10. 01-linux - kvm

    配置linux kvm 逻辑卷 # df -h # fdisk -l | grep dev # pvs # pvcreate /dev/sdg # pvs # vgcreate oradata /de ...