【BZOJ5496】[十二省联考2019]字符串问题(后缀树)

题面

BZOJ

洛谷

题解

首先显然可以把具有支配关系的串从\(A\)到\(B\)连一条有向边,如果\(B_i\)是\(A_j\)的前缀,就从\(B\)连一条边到\(A\)。这样子问题就转化成了要求解这个二分图的最长路经,有环答案就是\(-1\)。

然后显然就是要找个什么东西出来优化连边是吧。。。

现在唯一要处理的东西就是要找到个啥玩意,来优化这个满足前缀条件的连边。

假装我们有一个所有后缀都被插进去的\(Trie\)树,那么对于每一个\(B\)只需要找到其对应的节点,然后它子树中的每一个\(A\)都会被他连过去,这样子似乎就达成了优化连边,即每一个\(B\)连向这个节点,然后这样节点连向在这个节点终止的\(A\)。

这个复杂度显然是爆炸的,所以我们可以直接建立后缀树,这样子节点数就被优化到了\(O(n)\)级别。

于是问题又出现了,在后缀树上的一个节点表示的长度是一段区间,假如一个节点上又挂了\(A\),又挂了\(B\)就会出锅。(虽然不管这个也有\(80\)分了)

那行啊,我们来拆个点,每个树上节点拆两个,一个\(u\)负责挂好所有儿子,另外一个\(v\)负责挂好所有在这个点的\(A\),然后所有的\(A\)按照长度从小往大挂成一条链。然后\(v\)指向\(u\),这样子任何一个\(B\)对应的一定是一段后缀\(A\),所以直接后缀优化连边连向这条链,然后再连向\(u\)表示指向所有的儿子。

这样子还是很麻烦,实际上有一个更加优秀的做法,就是对于一个点如果挂了多个串,那么就按照每个串长把这个点强行拆掉就行了(虽然本质上就是挂了一条链)。

于是只需要求解最长路就行了,而且还是树上的最长链,只需要按照拓扑序做就行了,即使有环也可以在这个过程中处理掉。

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<vector>
#include<queue>
using namespace std;
#define ll long long
#define MAX 800800
#define pb push_back
inline int read()
{
int x=0;bool t=false;char ch=getchar();
while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
if(ch=='-')t=true,ch=getchar();
while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
return t?-x:x;
}
vector<int> E[MAX],W[MAX],str[MAX];
char ch[MAX];int Len;
int fa[20][MAX],pos[MAX],val[MAX];
struct Node{int son[26],len,ff;void clear(){memset(son,0,sizeof(son));len=ff=0;}}t[MAX];
int last=1,tot=1;
void extend(int c)
{
int p=last,np=++tot;last=np;
t[np].len=t[p].len+1;
while(p&&!t[p].son[c])t[p].son[c]=np,p=t[p].ff;
if(!p)t[np].ff=1;
else
{
int q=t[p].son[c];
if(t[q].len==t[p].len+1)t[np].ff=q;
else
{
int nq=++tot;
t[nq]=t[q];t[nq].len=t[p].len+1;
t[q].ff=t[np].ff=nq;
while(p&&t[p].son[c]==q)t[p].son[c]=nq,p=t[p].ff;
}
}
}
vector<int> ee[MAX];
void dfs(int u,int ff)
{
fa[0][u]=ff;
for(int i=1;i<20;++i)fa[i][u]=fa[i-1][fa[i-1][u]];
for(int i=0,l=ee[u].size();i<l;++i)dfs(ee[u][i],u);
}
void Work()
{
Len=strlen(ch+1);
for(int i=Len;i;--i)extend(ch[i]-97),pos[i]=last;
for(int i=1;i<=tot;++i)ee[t[i].ff].pb(i);
dfs(1,0);
}
int TOT,nd[MAX],IDA[MAX],IDB[MAX],Lim[MAX],lenA[MAX];
void Add(int u,int v,int w){if(u)E[u].pb(v),W[u].pb(w);}
bool cmp(int a,int b){return lenA[a]<lenA[b];}
void Build(int u,int ff)
{
int np=++TOT;nd[u]=np;Lim[np]=t[u].len;
if(ff)
{
int lst=ff;
for(int i=0,l=str[u].size();i<l;++i)
{
Add(lst,++TOT,0),val[TOT]=lenA[str[u][i]],fa[0][TOT]=lst,Lim[TOT]=lenA[str[u][i]],lst=TOT;
IDA[str[u][i]]=TOT;
}
Add(lst,np,0);fa[0][np]=lst;
}
for(int i=0,l=ee[u].size();i<l;++i)Build(ee[u][i],np);
}
int deg[MAX];ll dis[MAX],ans;
void Topsort()
{
for(int i=1;i<=TOT;++i)
for(int j=0,l=E[i].size();j<l;++j)
deg[E[i][j]]+=1;
queue<int> Q;int QwQ=0;
for(int i=1;i<=TOT;++i)if(!deg[i])Q.push(i);
while(!Q.empty())
{
int u=Q.front();Q.pop();QwQ+=1;
ans=max(ans,dis[u]+val[u]);
for(int i=0,l=E[u].size();i<l;++i)
{
int v=E[u][i];
dis[v]=max(dis[v],dis[u]+W[u][i]);
if(!--deg[v])Q.push(v);
}
}
if(QwQ<TOT)puts("-1");
else printf("%lld\n",ans);
}
int main()
{
int T=read();
while(T--)
{
scanf("%s",ch+1);
Work();
int A=read();
for(int i=1;i<=A;++i)
{
int l=read(),r=read(),len=r-l+1;
int u=pos[l];lenA[i]=len;
for(int i=19;~i;--i)
if(t[fa[i][u]].len>=len)u=fa[i][u];
str[u].pb(i);
}
for(int i=1;i<=tot;++i)sort(str[i].begin(),str[i].end(),cmp);
for(int i=0;i<=tot;++i)
for(int j=0;j<20;++j)fa[j][i]=0;
Build(1,0);
for(int j=1;j<20;++j)
for(int i=1;i<=TOT;++i)
fa[j][i]=fa[j-1][fa[j-1][i]];
int B=read();
for(int i=1;i<=B;++i)
{
int l=read(),r=read(),len=r-l+1;IDB[i]=++TOT;
int u=nd[pos[l]];
for(int j=19;~j;--j)
if(Lim[fa[j][u]]>=len)u=fa[j][u];
Add(IDB[i],u,0);
}
int C=read();
while(C--)
{
int x=read(),y=read();
Add(IDA[x],IDB[y],lenA[x]);
}
Topsort();
for(int i=0;i<=TOT;++i)
{
ee[i].clear();E[i].clear();t[i].clear();
str[i].clear();W[i].clear();
for(int j=0;j<20;++j)fa[j][i]=0;
IDA[i]=IDB[i]=Lim[i]=pos[i]=deg[i]=0;
dis[i]=ans=val[i]=lenA[i]=nd[i]=0;
}
last=tot=1;TOT=0;
}
return 0;
}

【BZOJ5496】[十二省联考2019]字符串问题(后缀树)的更多相关文章

  1. 洛谷P5284 [十二省联考2019]字符串问题 [后缀树]

    传送门 思路 设\(dp_i\)表示以\(i\)结尾的\(A\)串,能达到的最长长度. 然后发现这显然可以\(i\)往自己控制的\(k\)连边,\(k\)往能匹配的\(j\)连边,就是个最长路,只要建 ...

  2. [十二省联考2019]字符串问题——后缀自动机+parent树优化建图+拓扑序DP+倍增

    题目链接: [十二省联考2019]字符串问题 首先考虑最暴力的做法就是对于每个$B$串存一下它是哪些$A$串的前缀,然后按每组支配关系连边,做一遍拓扑序DP即可. 但即使忽略判断前缀的时间,光是连边的 ...

  3. 洛谷.5284.[十二省联考2019]字符串问题(后缀自动机 拓扑 DP)

    LOJ BZOJ 洛谷 对这题无话可说,确实比较...裸... 像dls说的拿拓扑和parent树一套就能出出来了... 另外表示BZOJ Rank1 tql... 暴力的话,由每个\(A_i\)向它 ...

  4. [LOJ3049] [十二省联考 2019] 字符串问题

    题目链接 LOJ:https://loj.ac/problem/3049 洛谷:https://www.luogu.org/problemnew/show/P5284 BZOJ:https://www ...

  5. P5284 [十二省联考2019]字符串问题

    这是一道涵盖了字符串.图论.数据结构三个方面的综合大题. 把这道题放在D1T2的人应该拖出去打 前置芝士 首先,您至少要会topsort. 其次,如果您只想拿个暴力分,字符串Hash就足够了:如果您想 ...

  6. Luogu P5284 [十二省联考2019]字符串问题

    好难写的字符串+数据结构问题,写+调了一下午的说 首先理解题意后我们对问题进行转化,对于每个字符串我们用一个点来代表它们,其中\(A\)类串的点权为它们的长度,\(B\)类串的权值为\(0\) 这样我 ...

  7. LOJ3049 [十二省联考2019] 字符串问题 【后缀自动机】【倍增】【拓扑排序】

    题目分析: 建出后缀自动机,然后把A串用倍增定位到后缀自动机上,再把B串用倍增定位到后缀自动机上. SAM上每个点上的A串根据长度从小到大排序,建点,依次连边. 再对于SAM上面每个点,连到儿子的边, ...

  8. 【题解】Luogu P5284 [十二省联考2019]字符串问题

    原题传送门 我用sa做的本题 (码量似乎有点大) 先对原串建sa 考虑如何建图: 从大到小枚举长度len 先将height中等于len的两个位置在并查集合并起来,将lst也合并(lst是链表) 再将长 ...

  9. Luogu5289 十二省联考2019字符串问题(后缀数组+拓扑排序+线段树/主席树/KDTree)

    先考虑80分做法,即满足A串长度均不小于B串,容易发现每个B串对应的所有A串在后缀数组上都是一段连续区间,线段树优化连边然后判环求最长链即可.场上就写了这个. 100分也没有什么本质区别,没有A串长度 ...

随机推荐

  1. Windchill基本业务对象-文档

    文档的类型: (1)WTDocumetManster :是文档的主要信息,一个文档只有一条记录:(2)WTDocument:是文档小版本记录,每一个文档小版本都有一条记录: 备注:(1)文档大版本记录 ...

  2. ionic3 Modal组件

     Modal组件主要用来弹出一些临时的框,如登录,注册的时候用 弹出页面html页面 <button ion-button small outline color="he" ...

  3. 牛客网:java入门实现遍历目录

    项目介绍 遍历目录是操作文件时的一个常见需求.比如写一个程序,需要找到并处理指定目录下的所有JS文件时,就需要遍历整个目录.该项目教会你如何使用流式编程和lambda表达式,帮助你进一步熟悉java8 ...

  4. java设计模式——适配器模式 Java源代码

    前言:适配器模式就是把一个类的接口变换成客户端所能接受的另一种接口,从而使两个接口不匹配而无法在一起工作的两个类能够在一起工作.通常被用在一个项目需要引用一些开源框架来一起工作时,这些框架的内部都有一 ...

  5. C语言运行库翻译

    这是从Visual C++ 6里面的C语言部分翻译过来. http://files.cnblogs.com/files/sishenzaixian/C运行库.zip

  6. 推荐六款炫酷的HTML5效果插件

    1. HTML5 3D图片阴影翻转动画 效果很酷 分享一款很酷的HTML5 3D动画特效,这款3D特效可以为你的图片增加阴影的效果,而且可以让图片在鼠标滑过的时候出现3D翻转的动画效果.这和HTML5 ...

  7. 【实战代码】PHP实现读取一个1G的文件大小

    本文地址:http://www.cnblogs.com/aiweixiao/p/7535351.html 欢迎关注我的微信公众号哈 “ 程序员的文娱情怀” http://t.cn/RotyZtu [背 ...

  8. 【English】20190416

     anti-money laundering反洗钱[ˈænti][ˈlɔːndərɪŋ] misconduct不当行为[ˌmɪsˈkɑːndʌkt]   Currently, she is focus ...

  9. Storm入门(三)HelloWorld示例

    一.配置开发环境 storm有两种操作模式: 本地模式和远程模式.使用本地模式的时候,你可以在你的本地机器上开发测试你的topology, 一切都在你的本地机器上模拟出来; 用远程模式的时候你提交的t ...

  10. web框架开发-Ajax

    Ajax简介 向服务器发送请求的4种方式 1.浏览器地址栏,默认get请求2.form表单: get请求 post请求3.a标签,默认get请求 4.Ajax 特点: 1 异步请求 2 局部刷新 方式 ...