题目大意

给出字符串\(S(|S|\leq2\times10^5)\),

\(na(na\leq2\times 10^5)\)个区间\([l_i,r_i]\)表示\(S_{l_i},S_{l_i+1},...,S_{r_i}\)组成的这个\(S\)的子串是第\(i\)个A类串

\(nb(nb\leq2\times 10^5)\)个区间\([l_i,r_i]\)表示\(S_{l_i},S_{l_i+1},...,S_{r_i}\)组成的这个\(S\)的子串是第\(i\)个B类串

\(m(m\leq2\times10^5)\)个限制条件\((x,y)\)表示第\(x\)个A类串后面可以接以第\(y\)个B类串为前缀的A类串

现在想要生成字符串\(T\),满足\(T\)由若干个A类串拼接而成,而且相邻的A类串之间满足限制条件

求\(T\)的最长长度,或判断\(T\)可以无限长

题解

发现将每个A类串看成一个点,点权为它的长度,将每个A类串向它后面能接的A类串连边

问题就变成了找环或求点权之和最大的链

暴力连边肯定不行,考虑后缀树优化建图

连出的边的形态大概是:\(A_i->B_i->以B_i为前缀的A\)

那么考虑将后缀树上的每个点\(x\)拆成两个点\(x_A,x_B\)

要连的边就是:\(x_B->x_A,x_{A_i}->x_{B_i}\)和从\(x_B\)连向它后缀树的儿子的\(x_B\)的边

还有个问题:已知区间\([l,r]\),在\(S\)的后缀树中找到\(S[l:r]\)对应的点

后缀树中每个叶子结点是\(S\)的后缀,父亲是儿子的前缀

那么对于\(\forall i\in[1,|S|]\)可以在建后缀树时记\(S[i:|S|]\)的位置

找\(S[l:r]\)对应的位置就变成了先找\(S[l:|S|]\)的位置,再在这个点的祖先中找到\(dis\)值不小于\(r-l+1\)的最高点

这一步可以预处理每个点第\(2^k\)个祖先+倍增

还有一点要注意的是,后缀树中的每个点可能代表了多个串,所以还要再把每个点内部拆一次

并没有想象中那么难写

代码
#include<algorithm>
#include<cmath>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<ctime>
#include<iomanip>
#include<iostream>
#include<map>
#include<queue>
#include<set>
#include<stack>
#include<vector>
#define rep(i,x,y) for(register int i=(x);i<=(y);++i)
#define dwn(i,x,y) for(register int i=(x);i>=(y);--i)
#define view(u,k) for(int k=fir[u];~k;k=nxt[k])
#define maxn 200010
#define maxm (maxn<<1)
#define LL long long
#define pb push_back
using namespace std;
int read()
{
int x=0,f=1;char ch=getchar();
while(!isdigit(ch)&&ch!='-')ch=getchar();
if(ch=='-')f=-1,ch=getchar();
while(isdigit(ch))x=(x<<1)+(x<<3)+ch-'0',ch=getchar();
return x*f;
}
void write(LL x)
{
if(x==0){putchar('0'),putchar('\n');return;}
int f=0;char ch[20];
if(x<0)putchar('-'),x=-x;
while(x)ch[++f]=x%10+'0',x/=10;
while(f)putchar(ch[f--]);
putchar('\n');
return;
}
char s[maxn];
int dfn[maxm<<2],in[maxm<<2],yes,n,ch[maxm][26],dis[maxm],fa[maxm],posa[maxn],posb[maxn],pos[maxn],rt,cntnd,lst,c[maxn],ord[maxm];
int m,T,na,nb,fir[maxm<<2],nxt[maxm<<3],v[maxm<<3],cnte,anc[maxm][20],low[maxm<<2],ins[maxm<<2],tim,stk[maxm<<2],tp,tot;
int Q[maxm<<2],hd,tl,ltha[maxn],lthb[maxn];
LL maxd[maxm<<2],ans;
int w[maxm<<2];
vector <int >val[maxm],id[maxm];
#define gx(C) (C-'a')
void ade(int u1,int v1){v[cnte]=v1,nxt[cnte]=fir[u1],fir[u1]=cnte++;}
void ext(int i)
{
int p=lst,val=gx(s[i]),np=++cntnd;dis[np]=i,lst=np,pos[n-i+1]=np;
for(;p&&!ch[p][val];p=fa[p])ch[p][val]=np;
if(!p)fa[np]=rt;
else
{
int q=ch[p][val];
if(dis[p]+1==dis[q])fa[np]=q;
else
{
int nq=++cntnd;
dis[nq]=dis[p]+1;
memcpy(ch[nq],ch[q],sizeof(ch[q]));
fa[nq]=fa[q],fa[q]=fa[np]=nq;
for(;p&&ch[p][val]==q;p=fa[p])ch[p][val]=nq;
}
}
}
void reset()
{
rep(i,1,n)c[i]=0;
rep(i,1,cntnd)rep(j,0,25)ch[i][j]=0;
rep(i,1,cntnd)rep(j,0,19)anc[i][j]=0;
rep(i,1,cntnd){fa[i]=0;}
dwn(i,(tot<<1),1)dfn[i]=in[i]=maxd[i]=0,fir[i]=-1,w[i]=0;
rt=lst=cntnd=hd=1;tl=cnte=yes=ans=tim=tp=tot=0;
}
int getp(int l,int r)
{
int len=r-l+1,u=pos[l];
dwn(i,19,0)if(anc[u][i]&&dis[anc[u][i]]>=len)u=anc[u][i];
return u;
}
void tar(int u)
{
dfn[u]=low[u]=++tim;
ins[u]=1,stk[++tp]=u;
view(u,k)
{
if(!dfn[v[k]])tar(v[k]),low[u]=min(low[u],low[v[k]]);
else if(ins[v[k]])low[u]=min(low[u],dfn[v[k]]);
}
if(low[u]==dfn[u])
{
int num=0;
while(1)
{
num++;
ins[stk[tp]]=0;
if(stk[tp--]==u)break;
}
if(num>1)yes=1;
}
}
int getpos(int u,int len)
{
int l=0,r=val[u].size()-1,res=r;
while(l<=r)
{
int mid=(l+r)>>1;
if(val[u][mid]>=len)res=min(res,mid),r=mid-1;
else l=mid+1;
}
return id[u][res];
}
int main()
{
T=read();
memset(fir,-1,sizeof(fir));rt=lst=++cntnd;hd=1,tl=0;
while(T--)
{
scanf("%s",s+1);
n=strlen(s+1);
reverse(s+1,s+n+1);
rep(i,1,n)ext(i);
rep(i,1,cntnd)c[dis[i]]++;
rep(i,1,n)c[i]+=c[i-1];
rep(i,1,cntnd)ord[c[dis[i]]--]=i;
rep(j,1,cntnd)
{
int i=ord[j];
anc[i][0]=fa[i];
rep(k,1,19)anc[i][k]=anc[anc[i][k-1]][k-1];
}
na=read();
rep(i,1,na){int l=read(),r=read();posa[i]=getp(l,r),val[posa[i]].pb(r-l+1),ltha[i]=r-l+1;}
nb=read();
rep(i,1,nb){int l=read(),r=read();posb[i]=getp(l,r),lthb[i]=r-l+1;}
rep(i,1,cntnd)sort(val[i].begin(),val[i].end());
rep(j,1,cntnd)
{
int lim=val[ord[j]].size(),Lst=0;if(fa[ord[j]]){Lst=id[fa[ord[j]]][id[fa[ord[j]]].size()-1];}
rep(k,0,lim-1){++tot,w[tot]=val[ord[j]][k];if(fa[ord[j]])ade(Lst,tot),++in[tot];Lst=tot,id[ord[j]].pb(tot);}
if(!lim||val[ord[j]][lim-1]!=dis[ord[j]]){++tot;if(fa[ord[j]])ade(Lst,tot),++in[tot];id[ord[j]].pb(tot);val[ord[j]].pb(dis[ord[j]]);}
}
m=read();
rep(i,1,tot)ade(i,i+tot),++in[i+tot],w[i+tot]=w[i],w[i]=0;
rep(i,1,m)
{
int x=read(),y=read();
x=getpos(posa[x],ltha[x]),y=getpos(posb[y],lthb[y]);
ade(x+tot,y),in[y]++;
}
{rep(i,1,cntnd){val[i].clear(),val[i].shrink_to_fit();id[i].clear(),id[i].shrink_to_fit();}}
dwn(i,(tot<<1),1)if(!dfn[i])tar(i);
if(yes)puts("-1");
else
{
dwn(i,(tot<<1),1)if(!in[i])Q[++tl]=i;
while(hd<=tl)
{
int u=Q[hd++];maxd[u]+=w[u],ans=max(ans,maxd[u]);
view(u,k)
{
maxd[v[k]]=max(maxd[v[k]],maxd[u]),in[v[k]]--;
if(!in[v[k]])Q[++tl]=v[k];
}
}
write(ans);
}
reset();
}
return 0;
}
一些感想

据说猎人公会会长是云猎人。。。我佛了

sb猎人公会nmsl

并不对劲的loj3049:p5284:[十二省联考]字符串问题的更多相关文章

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

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

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

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

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

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

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

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

  5. 洛谷P5284 [十二省联考2019]字符串问题(SAM+倍增+最长路)

    题面 传送门 题解 首先,我们把串反过来,那么前缀就变成后缀,建一个\(SAM\).我们发现一个节点的后缀是它的所有祖先 那么我们是不是直接按着\(parent\)树建边就可以了呢? 显然不是.我们假 ...

  6. 并不对劲的loj3048:p5283:[十二省联考]异或粽子

    题目大意 有\(n\)(\(n\leq5\times10^5\))个数\(a_1,a_2,...a_n\)(\(a_i\leq 2^{32}-1\)) 求区间异或和前\(k(k\leq2\times1 ...

  7. CQOI2019(十二省联考)游记

    CQOI2019(十二省联考)游记 Day -? 自从联赛爆炸,\(THUWC\)爆炸,\(WC\)爆炸(就没有不爆炸的)之后我已经无所畏惧... 听说是考\(4.5 h\)吗? Day -1 \(Z ...

  8. 2019十二省联考 Round 1 && 济南市市中心游记

    在这样一场毒瘤的省选中 这道题目无疑是命题人无私的馈赠 大量精心构造的部分分,涵盖了题目中所有涉及的算法 你可以利用这道题目,对你是否能够进入省队进行初步检查 经典的模型.较低的难度和不大的代码量,能 ...

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

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

随机推荐

  1. GOPATH设置

    go help gopath查看gopath的原文帮助信息 go env查看gopath的配置 GOPATH与工作空间 前面我们在安装Go的时候看到需要设置GOPATH变量,Go从1.1版本到1.7必 ...

  2. const mutable

    在C++中,由const修饰的成员函数的函数体内部,是不能够对成员变量进行修改的.这个特性被用来保证某些成员函数在实现过程中,避免由于程序员大意而对数据进行了错误的修改:同时也说明此成员函数是非修改性 ...

  3. 第四讲_图像识别之图像分类Image Classification

    第四讲_图像识别之图像分类Image Classification 目录 图片分类 性能指标:top1,top5 ILSVRC:每种任务数据集不一样 imageNet:根据WorldNet组织的图片集 ...

  4. JAVA Timer定时器使用方法

    JAVA  Timer 定时器测试 MyTask.java:package com.timer; import java.text.SimpleDateFormat;import java.util. ...

  5. Quality control

    定义测试         为测试添加测试项     测试项目按类型分2种 Qualitative 定性,描述类的,比如颜色,是,否 Quantitative 定量,有明确的衡量         定性 ...

  6. matplotlib简易新手教程及动画

    做数据分析,首先是要熟悉和理解数据.所以掌握一个趁手的可视化工具是很重要的,否则对数据连个主要的感性认识都没有,怎样进行下一步的design 点击打开链接 还有一个非常棒的资料  Matplotlib ...

  7. 使用excel进行数据挖掘(5)---- 应用场景分析

    使用excel进行数据挖掘(5)---- 应用场景分析 在配置环境后,能够使用excel进行数据挖掘. 环境配置问题可參阅: http://blog.csdn.net/xinxing__8185/ar ...

  8. mysql字符太长警告

    用navicateclient,打开相应的数据库. 打开函数.找相应的val()函数,进行编辑,就能够!编辑范围为4000

  9. 简单vi配置:YouCompleteMe

    下图就是我的VI: 按F5 F6分别调出左右的窗体: 按C-P点出CtrlP搜索,直接查找project中的文件: 自己主动补全用的YouCompleteMe.超级强悍: watermark/2/te ...

  10. project 2013 激活 key 7YHNW-RVCQY-VBDB2-QX69Q-B96WK viso 66DNF-28W69-W4PPV-W3VYT-TJDBQ

    project 2013 激活 key :7YHNW-RVCQY-VBDB2-QX69Q-B96WK viso2013  激活 key:66DNF-28W69-W4PPV-W3VYT-TJDBQ 软件 ...