[bzoj3879][后缀自动机][虚树]SvT

2023-10-16 03:08

本文主要是介绍[bzoj3879][后缀自动机][虚树]SvT,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

Description

(我并不想告诉你题目名字是什么鬼)

有一个长度为n的仅包含小写字母的字符串S,下标范围为[1,n].

现在有若干组询问,对于每一个询问,我们给出若干个后缀(以其在S中出现的起始位置来表示),求这些后缀两两之间的LCP(LongestCommonPrefix)的长度之和.一对后缀之间的LCP长度仅统计一遍.

Input

第一行两个正整数n,m,分别表示S的长度以及询问的次数.

接下来一行有一个字符串S.

接下来有m组询问,对于每一组询问,均按照以下格式在一行内给出:

首先是一个整数t,表示共有多少个后缀.接下来t个整数分别表示t个后缀在字符串S中的出现位置.

Output

对于每一组询问,输出一行一个整数,表示该组询问的答案.由于答案可能很大,仅需要输出这个答案对于23333333333333333(一个巨大的质数)取模的余数.

Sample Input

7 3

popoqqq

1 4

2 3 5

4 1 2 5 6

Sample Output

0

0

2

HINT

样例解释:

对于询问一,只有一个后缀”oqqq”,因此答案为0.

对于询问二,有两个后缀”poqqq”以及”qqq”,两个后缀之间的LCP为0,因此答案为0.

对于询问三,有四个后缀”popoqqq”,”opoqqq”,”qqq”,”qq”,其中只有”qqq”,”qq”两个后缀之间的LCP不为0,且长度为2,因此答案为2.

对于100%的测试数据,有S<=5*105,且Σt<=3*106.

特别注意:由于另一世界线的某些参数发生了变化,对于一组询问,即使一个后缀出现了多次,也仅算一次.

题解

存板
题解在SAM的一些题里面…

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<cmath>
#include<queue>
#include<vector>
#include<ctime>
#include<map>
#include<bitset>
#include<set>
#define LL long long
#define mp(x,y) make_pair(x,y)
#define pll pair<long long,long long>
#define pii pair<int,int>
using namespace std;
inline int read()
{int f=1,x=0;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}return x*f;
}
int stack[20];
inline void write(LL x)
{if(x<0){putchar('-');x=-x;}if(!x){putchar('0');return;}int top=0;while(x)stack[++top]=x%10,x/=10;while(top)putchar(stack[top--]+'0');
}
inline void pr1(int x){write(x);putchar(' ');}
inline void pr2(LL x){write(x);putchar('\n');}
const int MAXN=2*500005;
struct SAM
{int son[30],dep,parent;
}tr[MAXN];int cnt,lst,root;
void add(int x)
{int np=++cnt,p=lst;tr[np].dep=tr[p].dep+1;while(p&&tr[p].son[x]==0)tr[p].son[x]=np,p=tr[p].parent;if(!p)tr[np].parent=root;else{int q=tr[p].son[x];if(tr[q].dep==tr[p].dep+1)tr[np].parent=q;else{int nq=++cnt;tr[nq]=tr[q];tr[nq].dep=tr[p].dep+1;tr[q].parent=tr[np].parent=nq;while(p&&tr[p].son[x]==q)tr[p].son[x]=nq,p=tr[p].parent;}}lst=np;
}
struct edge{int x,y,next;}a[2*MAXN];int len,last[MAXN];
void ins(int x,int y){len++;a[len].x=x;a[len].y=y;a[len].next=last[x];last[x]=len;}
int bin[25],fa[25][MAXN],dep[MAXN],in[MAXN],pos[MAXN],dfn;
void pre_tree_node(int x)
{in[x]=++dfn;for(int i=1;bin[i]<=dep[x];i++)fa[i][x]=fa[i-1][fa[i-1][x]];for(int k=last[x];k;k=a[k].next){int y=a[k].y;fa[0][y]=x;dep[y]=dep[x]+1;pre_tree_node(y);}
}
int lca(int x,int y)
{if(dep[x]<dep[y])swap(x,y);for(int i=20;i>=0;i--)if(bin[i]<=dep[x]&&dep[fa[i][x]]>=dep[y])x=fa[i][x];if(x==y)return x;for(int i=20;i>=0;i--)if(bin[i]<=dep[x]&&fa[i][x]!=fa[i][y])x=fa[i][x],y=fa[i][y];return fa[0][x];
}
char ch[MAXN];
int m,id[MAXN],vis[MAXN],ok[MAXN],tim,ln;
bool cmp(int n1,int n2){return in[pos[n1]]<in[pos[n2]];}
int sta[MAXN],tp;
void insert(int u)
{if(tp<=1){sta[++tp]=u;return ;}int LA=lca(sta[tp],u);if(LA==sta[tp]){if(sta[tp]!=u)sta[++tp]=u;return ;}while(tp>1&&in[sta[tp-1]]>=in[LA])ins(sta[tp-1],sta[tp]),tp--;if(sta[tp]!=LA)ins(LA,sta[tp]),sta[tp]=LA;sta[++tp]=u;
}
LL ans,tot[MAXN];
int gg[MAXN];
void solve(int x)
{tot[x]=ok[x];ok[x]=0;for(int k=last[x];k;k=a[k].next){int y=a[k].y;solve(y);ans+=1LL*tot[x]*tot[y]*tr[x].dep;tot[x]+=tot[y];}
}
int main()
{bin[0]=1;for(int i=1;i<=20;i++)bin[i]=bin[i-1]<<1;int n=read();m=read();scanf("%s",ch+1);reverse(ch+1,ch+1+n);cnt=lst=root=1;for(int i=1;i<=n;i++)add(ch[i]-'a'+1),pos[i]=lst;for(int i=1;i<=cnt;i++)if(tr[i].parent)ins(tr[i].parent,i);pre_tree_node(1);while(m--){int N=read();tim++;ln=0;for(int i=1;i<=N;i++){int x=n-read()+1;if(vis[x]==tim)continue;vis[x]=tim;id[++ln]=x;ok[pos[x]]=1;}sort(id+1,id+1+ln,cmp);for(int i=1;i<=len;i++)last[a[i].x]=last[a[i].y]=0;len=tp=0;sta[tp=1]=1;for(int i=1;i<=ln;i++)insert(pos[id[i]]);while(tp>1)ins(sta[tp-1],sta[tp]),tp--;ans=0;solve(1);pr2(ans);}return 0;
}

这篇关于[bzoj3879][后缀自动机][虚树]SvT的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/218589

相关文章

hdu 3065 AC自动机 匹配串编号以及出现次数

题意: 仍旧是天朝语题。 Input 第一行,一个整数N(1<=N<=1000),表示病毒特征码的个数。 接下来N行,每行表示一个病毒特征码,特征码字符串长度在1—50之间,并且只包含“英文大写字符”。任意两个病毒特征码,不会完全相同。 在这之后一行,表示“万恶之源”网站源码,源码字符串长度在2000000之内。字符串中字符都是ASCII码可见字符(不包括回车)。

POJ 1625 自动机

给出包含n个可见字符的字符集,以下所提字符串均由该字符集中的字符构成。给出p个长度不超过10的字符串,求长为m且不包含上述p个字符串的字符串有多少个。 g++提交 int mat[108][108] ;int matn ;int N ;map<char ,int> to ;//ACconst int maxm = 108 ;const int kin

zoj 3228 ac自动机

给出一个字符串和若干个单词,问这些单词在字符串里面出现了多少次。单词前面为0表示这个单词可重叠出现,1为不可重叠出现。 Sample Input ab 2 0 ab 1 ab abababac 2 0 aba 1 aba abcdefghijklmnopqrstuvwxyz 3 0 abc 1 def 1 jmn Sample Output Case 1 1 1 Case 2

将浮点型算式的中缀表达式转换成后缀表达式并算出式子结果

最近因为需要了解如何将在Win应用程序控制台输入的算式表达式转化成其后缀表达式的算法,所以在网上搜索了一下,看到许多人的程序都只是对应于运算数在0~9的范围内的整型运算式,所以自己就写了一个可以计算浮点型算式的程序,一下是运行时的截图: 式子中的a,b,c是可供用户自行输入的变量。 首先,我先对输入的运算符进行了简单的合法性判断,我的判断代 码如下: //函数的传入参

正规式与有限自动机例题

答案:D 知识点: 正规式 正规集 举例 ab 字符串ab构成的集合 {ab} a|b 字符串a,b构成的集合 {a,b} a^* 由0或者多个a构成的字符串集合 {空,a,aa,aaa,aaaa····} (a|b)^* 所有字符a和b构成的串的集合 {空,a,b,ab,aab,aba,aaab····} a(a|b)^* 以a为首字符的a,b字符串的集

后缀表达式转中缀表达式

假定有后缀表达式1 2 3 + 4 * +5 – ,请将它转化为前缀表达式。 利用表达式树: 1.从左到右扫面后缀表达式,一次一个符号读入表达式。2.如果符号是操作数,那么就建立一个单节点树并将它推入栈中。如果符号是操作符,那么就从栈中弹出两个树T1和T2(T1先弹出)并形成一颗新的树,该树的根就是操作符,它的左、右儿子分别是T2和T1(先出的为右子树,后出的为左子树)。然后将指向这棵新树的指

什么是顶级域名后缀?

在互联网发展的历程中,顶级域名(Top-Level Domain,简称TLD)扮演着至关重要的角色。而这些顶级域名的后缀,则更是成为了整个网络世界的分类标准和识别依据。 顶级域名后缀,通常指位于域名最右端的部分,如".com"、“.org”、".cn"等。它们为下层的二级域名和三级域名提供了一个基础的分类框架,让互联网上的各类网站、组织和个人能够根据自身特点选择合适的域名后缀。 不同类型的顶级

AC自动机 - 多模式串的匹配运用 --- HDU 3065

病毒侵袭持续中  Problem's Link:http://acm.hdu.edu.cn/showproblem.php?pid=3065   Mean:  略 analyse:  AC自动机的运用. 这一题需要将模式串都存储下来,还有就是base的取值一定要弄清楚,由于这题的模式串都是大写字母所以我们可以通过剪枝来加速。 Time complexity:o(n)+o(m

AC自动机 - 多模式串的匹配运用 --- HDU 2896

病毒侵袭 Problem's Link:http://acm.hdu.edu.cn/showproblem.php?pid=2896   Mean:   略 analyse: AC自动机的运用,多模式串匹配。就是有几个细节要注意,在这些细节上卡了半天了。 1)输出的网站编号和最终的病毒网站数不是一样的; 2)next指针要设128,不然会爆栈; 3)同理,char转换为i

后缀数组 - 求最长回文子串 + 模板题 --- ural 1297

1297. Palindrome Time Limit: 1.0 second Memory Limit: 16 MB The “U.S. Robots” HQ has just received a rather alarming anonymous letter. It states that the agent from the competing «Robots Unlim