题面

传送门

题解

首先,我们把串反过来,那么前缀就变成后缀,建一个\(SAM\)。我们发现一个节点的后缀是它的所有祖先

那么我们是不是直接按着\(parent\)树建边就可以了呢?

显然不是。我们假设在\(SAM\)的某个节点上同时存在某个\(a_i\)和\(b_j\)且\(|b_j|>|a_i|\),\(b_j\)不是\(a_i\)的后缀,但它们仍然有边相连!(自己到自己就当有边吧……)

对于每一个节点,我们把处于这个节点中的所有串排个序,按长度为第一关键字,是否是\(B\)串为第二关键字。每个\(B\)串向最短的比它长的\(B\)串(记为\(S\))连边,并向所有比\(S\)短比自己长的\(A\)串连边。容易发现这样的边数是\(O(n)\)的

最后得到的图如果不是\(DAG\)无解,否则跑个最长路就可以了

//minamoto
#include<bits/stdc++.h>
#define inline __attribute__((always_inline))
#define R register
#define ll long long
#define fp(i,a,b) for(R int i=(a),I=(b)+1;i<I;++i)
#define fd(i,a,b) for(R int i=(a),I=(b)-1;i>I;--i)
#define go(u) for(int i=head[u],v=e[i].v;i;i=e[i].nx,v=e[i].v)
template<class T>inline bool cmax(T&a,const T&b){return a<b?a=b,1:0;}
using namespace std;
char buf[1<<21],*p1=buf,*p2=buf;
inline char getc(){return p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++;}
int read(){
R int res,f=1;R char ch;
while((ch=getc())>'9'||ch<'0')(ch=='-')&&(f=-1);
for(res=ch-'0';(ch=getc())>='0'&&ch<='9';res=res*10+ch-'0');
return res*f;
}
int read(char *s){
R int len=0;R char ch;while(((ch=getc())>'z'||ch<'a'));
for(s[++len]=ch;(ch=getc())>='a'&&ch<='z';s[++len]=ch);
return s[len+1]='\0',len;
}
const int N=1e6+5;
struct eg{int v,nx;}e[N];int head[N],deg[N],tot;
inline void add(R int u,R int v){e[++tot]={v,head[u]},head[u]=tot,++deg[v];}
int lst[N],ga[N][25],fa[N],l[N],pos[N],ch[N][26],cnt=1,las=1;
int n,lg,na,nb;char s[N];vector<int>g[N];
int A[N],B[N],st[N],len[N],top;
inline int newnode(R int len){return ++cnt,l[cnt]=len,memset(ch[cnt],0,104),cnt;}
inline int newnode(R int len,R int p){return ++cnt,l[cnt]=len,memcpy(ch[cnt],ch[p],104),cnt;}
bool cmp(const int &x,const int &y){return len[x]==len[y]?st[x]<st[y]:len[x]<len[y];}
void ins(int c){
int p=las,np=las=newnode(l[p]+1);
for(;p&&!ch[p][c];p=fa[p])ch[p][c]=np;
if(!p)fa[np]=1;
else{
int q=ch[p][c];
if(l[q]==l[p]+1)fa[np]=q;
else{
int nq=newnode(l[p]+1,q);
fa[nq]=fa[q],fa[q]=fa[np]=nq;
for(;ch[p][c]==q;p=fa[p])ch[p][c]=nq;
}
}
}
void Add(int p,int L,int is){
fd(i,lg,0)if(l[ga[p][i]]>=L)p=ga[p][i];
st[++top]=is,len[top]=L,g[p].push_back(top);
}
ll dis[N];int q[N],h,t;
ll topo(){
ll res=0;h=1,t=0;
fp(i,1,top){
if(!deg[i])q[++t]=i;
if(!st[i])len[i]=0;
}
while(h<=t){
int u=q[h++];cmax(res,dis[u]+len[u]);
go(u){
cmax(dis[v],dis[u]+len[u]);
if(!--deg[v])q[++t]=v;
}
}
fp(i,1,top)if(deg[i])return -1;
return res;
}
void clr(){
memset(st,0,(top+1)<<2);
memset(deg,0,(top+1)<<2);
memset(head,0,(top+1)<<2);
memset(dis,0,(top+1)<<3);
}
int main(){
// freopen("testdata.in","r",stdin);
for(int T=read();T;--T){
n=read(s),cnt=0,las=newnode(0),tot=0;
fd(i,n,1)ins(s[i]-'a'),pos[i]=las;
lg=log2(cnt)+1;
fp(i,1,cnt)ga[i][0]=fa[i];
fp(j,1,lg)fp(i,1,cnt)ga[i][j]=ga[ga[i][j-1]][j-1];
fp(i,1,cnt)g[i].clear();
top=cnt,na=read();
for(R int i=1,l,r;i<=na;++i)l=read(),r=read(),Add(pos[l],r-l+1,1),A[i]=top;
nb=read();
for(R int i=1,l,r;i<=nb;++i)l=read(),r=read(),Add(pos[l],r-l+1,0),B[i]=top;
fp(i,1,cnt)sort(g[i].begin(),g[i].end(),cmp);
for(R int i=1,now;i<=cnt;++i){
now=i;
fp(j,0,g[i].size()-1){
add(now,g[i][j]);
if(!st[g[i][j]])now=g[i][j];
}
lst[i]=now;
}
fp(i,2,cnt)add(lst[fa[i]],i);
for(R int x,y,i=read();i;--i)x=read(),y=read(),add(A[x],B[y]);
printf("%lld\n",topo());
clr();
}
return 0;
}

洛谷P5284 [十二省联考2019]字符串问题(SAM+倍增+最长路)的更多相关文章

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

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

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

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

  3. 洛谷.5283.[十二省联考2019]异或粽子(可持久化Trie 堆)

    LOJ 洛谷 考场上都拍上了,8:50才发现我读错了题=-= 两天都读错题...醉惹... \(Solution1\) 先求一遍前缀异或和. 假设左端点是\(i\),那么我们要在\([i,n]\)中找 ...

  4. 洛谷P5289 [十二省联考2019]皮配(01背包)

    啊啊啊边界判错了搞死我了QAQ 这题是一个想起来很休闲写起来很恶心的背包 对于\(k=0\)的情况,可以发现选阵营和选派系是独立的,对选城市选阵营和学校选派系分别跑一遍01背包就行了 对于\(k> ...

  5. 洛谷 5291 [十二省联考2019]希望(52分)——思路+树形DP

    题目:https://www.luogu.org/problemnew/show/P5291 考场上写了 16 分的.不过只得了 4 分. 对于一个救援范围,其中合法的点集也是一个连通块. 2n 枚举 ...

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

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

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

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

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

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

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

    [BZOJ5496][十二省联考2019]字符串问题(后缀树) 题面 BZOJ 洛谷 题解 首先显然可以把具有支配关系的串从\(A\)到\(B\)连一条有向边,如果\(B_i\)是\(A_j\)的前缀 ...

随机推荐

  1. U3D+SVN: 两份相同资源放在不同目录下导致META的更改

    U3D+SVN: 两份相同资源放在不同目录下导致META的更改. 实际情形:将地图文件map拷一份放在其它目录,回到UNITY编辑器,载入完成后加到磁盘,看到map文件夹下的所有meta都变红了. r ...

  2. Flume学习总结

    Flume学习总结 flume是一个用来采集数据的软件,它可以从数据源采集数据到一个集中存放的地方. 最常用flume的数据采集场景是对日志的采集,不过,lume也可以用来采集其他的各种各样的数据,因 ...

  3. manjaro i3 配置笔记

    更改国内源 sudo pacman-mirrors -GB testing -c China 增加Arch linuxcn源 在/etc/pacman.conf文件末尾添加两行: [archlinux ...

  4. Windows Python 2.7环境搭建

    一.安装及修改环境变量 我安装的版本是python-2.7.15.amd64,因为2.7.9之后的版本都会安装好pip.将Python执行文件所在文件夹加入path路径,C:\Python27.将pi ...

  5. 8-cin cout PK scanf printf(速度快慢问题对比)

    我们在c++ 中使用cin cout很方便但速度很慢,导致有些题目用cin就超时而用scanf则就ac了,那到底改用谁? cin慢是有原因的,其实默认的时候,cin与stdin总是保持同步的,也就是说 ...

  6. Illegal mix of collations for operation 'like' while searching with Ignited-Datatables

    Stack Overflow Questions Developer Jobs Tags Users   Log In Sign Up Join Stack Overflow to learn, sh ...

  7. Mybatis 实用篇(三)参数处理

    Mybatis 实用篇(三)参数处理 sql 语句中的参数 parameterType 可以省略不写. 一.参数封装 1.1 单个参数处理 public interface UserMapper { ...

  8. Python中where()函数的用法

    where()的用法 首先强调一下,where()函数对于不同的输入,返回的只是不同的. 1当数组是一维数组时,返回的值是一维的索引,所以只有一组索引数组 2当数组是二维数组时,满足条件的数组值返回的 ...

  9. 避免Block中的强引用环

    [避免Block中的强引用环] In manual reference counting mode, __block id x; has the effect of not retaining x. ...

  10. Android 4.0关于开机启动服务

    针对使用App应用管理强制停止的App,重启系统后不能收到开机启动, 需要运行一次后,在下次再启动时,才可以正确收到.