[十二省联考2019]字符串问题——后缀自动机+parent树优化建图+拓扑序DP+倍增
题目链接:
首先考虑最暴力的做法就是对于每个$B$串存一下它是哪些$A$串的前缀,然后按每组支配关系连边,做一遍拓扑序DP即可。
但即使忽略判断前缀的时间,光是连边的时间就会爆炸,显然不能暴力连边。
对于前缀不好解决,可以将字符串翻转然后变成判断是否是后缀。
可以发现对于后缀自动机的$parent$树,每个节点是子树内所有节点的后缀。
那么我们可以利用$parent$树来优化建图过程,将树上每个点向子节点连边。
对于每个$A$串和$B$串在后缀自动机上匹配出对应节点,如果是$A$串就新建节点并将$parent$树上的对应节点连向它,如果是$B$串就新建节点连向$parent$树上的对应节点。
对于$80\%$的数据,因为保证$B$串比$A$串短,所以对于$parent$树上的一个节点既有出点又有入点是合法的($100\%$的部分最后再说)。
但现在只解决了建图的问题,字符串在后缀自动机上匹配的时间复杂度依旧无法保证,如何找到每个$A,B$串对应的节点?
因为$[l,r]$的串一定是$[1,r]$的串的后缀,所以$[l,r]$的串在$parent$树上对应的节点一定是$[1,r]$的串对应节点的祖先,那么我们可以记录一下所有$[1,r]$的串在$parent$树上对应的节点,然后倍增往上跳来找到$[l,r]$对应的节点。
对于$100\%$的数据,不保证$B$串比$A$串短,那么就可能存在一个$B$串比一个$A$串长,但这两个串在$parent$树上对应的节点相同。如果像上述方式连边的话,就会导致这个$B$串能转移到$A$串。
对于这种情况,我们将连在$parent$树上同一点的所有串存起来,按长度从小到大为第一关键字、先$B$串后$A$串为第二关键字排序,将$parent$树上每个点与父节点之间的边拆开,在这两点之间建一串点,分别与排完序的$A,B$串新建点相连,再将这一串点依次相连,这样有了上下制约关系就不会导致上述情况发生了。
#include<set>
#include<map>
#include<queue>
#include<stack>
#include<cmath>
#include<cstdio>
#include<bitset>
#include<vector>
#include<cstring>
#include<iostream>
#include<algorithm>
#define ll long long
using namespace std;
int len[1200010];
int pre[1200010];
int tr[1200010][26];
int fa[1200010][19];
int num[200010];
int val[1200010];
int head[1200010];
int to[1400010];
int next[1400010];
int cnt;
int last;
int T;
int tot;
char ch[200010];
int na,nb;
int n,m;
int l,r;
int x,y;
int a[200010];
int b[200010];
int d[1200010];
queue<int>q;
int vis[1200010];
ll f[1200010];
int sum;
struct lty
{
int len,num,opt;
lty(){}
lty(int LEN,int NUM,int OPT){len=LEN,num=NUM,opt=OPT;}
bool operator <(lty a)const
{
return len==a.len?num>a.num:len<a.len;
}
};
vector<lty>v[400010];
inline void add(int x,int y)
{
next[++tot]=head[x];
head[x]=tot;
to[tot]=y;
d[y]++;
}
inline void insert(int x,int id)
{
int p=last;
int np=++cnt;
memset(tr[np],0,sizeof(tr[np]));
last=np;
len[np]=len[p]+1;
num[id]=np;
for(;p&&!tr[p][x];p=pre[p])
{
tr[p][x]=np;
}
if(!p)
{
pre[np]=1;
}
else
{
int q=tr[p][x];
if(len[q]==len[p]+1)
{
pre[np]=q;
}
else
{
int nq=++cnt;
memset(tr[nq],0,sizeof(tr[nq]));
len[nq]=len[p]+1;
pre[nq]=pre[q];
memcpy(tr[nq],tr[q],sizeof(tr[q]));
pre[q]=pre[np]=nq;
for(;p&&tr[p][x]==q;p=pre[p])
{
tr[p][x]=nq;
}
}
}
}
inline void build()
{
for(int i=2;i<=cnt;i++)
{
fa[i][0]=pre[i];
}
for(int j=1;j<=18;j++)
{
for(int i=2;i<=cnt;i++)
{
fa[i][j]=fa[fa[i][j-1]][j-1];
}
}
}
inline int ST(int x,int dis)
{
for(int i=18;i>=0;i--)
{
if(len[fa[x][i]]>=dis)
{
x=fa[x][i];
}
}
return x;
}
inline void clear()
{
for(int i=1;i<=sum;i++)
{
v[i].clear();
}
}
inline void solve()
{
scanf("%s",ch+1);
n=strlen(ch+1);
for(int i=1;i<=n;i++)
{
insert(ch[n-i+1]-'a',i);
}
build();
sum=cnt;
scanf("%d",&na);
for(int i=1;i<=na;i++)
{
scanf("%d%d",&l,&r);
a[i]=++cnt;
int p=ST(num[n-l+1],r-l+1);
v[p].push_back(lty(r-l+1,a[i],0));
val[a[i]]=r-l+1;
}
scanf("%d",&nb);
for(int i=1;i<=nb;i++)
{
scanf("%d%d",&l,&r);
b[i]=++cnt;
int p=ST(num[n-l+1],r-l+1);
v[p].push_back(lty(r-l+1,b[i],1));
}
for(int i=2;i<=sum;i++)
{
sort(v[i].begin(),v[i].end());
int sz=v[i].size();
int now=pre[i];
for(int j=0;j<sz;j++)
{
cnt++;
add(now,cnt);
if(!v[i][j].opt)
{
add(cnt,v[i][j].num);
}
else
{
add(v[i][j].num,cnt);
}
now=cnt;
}
add(now,i);
}
scanf("%d",&m);
for(int i=1;i<=m;i++)
{
scanf("%d%d",&x,&y);
add(a[x],b[y]);
}
for(int i=1;i<=cnt;i++)
{
f[i]=val[i];
if(!d[i])
{
q.push(i);
vis[i]=1;
}
}
while(!q.empty())
{
int now=q.front();
q.pop();
for(int i=head[now];i;i=next[i])
{
if(f[to[i]]<f[now]+val[to[i]])
{
f[to[i]]=f[now]+val[to[i]];
}
d[to[i]]--;
if(!d[to[i]])
{
q.push(to[i]);
vis[to[i]]=1;
}
}
}
ll ans=0;
for(int i=1;i<=cnt;i++)
{
if(!vis[i])
{
printf("-1\n");
clear();
return;
}
ans=max(ans,f[i]);
}
printf("%lld\n",ans);
clear();
}
inline void init()
{
cnt=last=1,tot=0;
memset(head,0,sizeof(head));
memset(to,0,sizeof(to));
memset(val,0,sizeof(val));
memset(num,0,sizeof(num));
memset(pre,0,sizeof(pre));
memset(tr[1],0,sizeof(tr[1]));
memset(next,0,sizeof(next));
memset(len,0,sizeof(len));
memset(d,0,sizeof(d));
memset(vis,0,sizeof(vis));
memset(f,0,sizeof(f));
}
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
init();
solve();
}
}
[十二省联考2019]字符串问题——后缀自动机+parent树优化建图+拓扑序DP+倍增的更多相关文章
- 洛谷.5284.[十二省联考2019]字符串问题(后缀自动机 拓扑 DP)
LOJ BZOJ 洛谷 对这题无话可说,确实比较...裸... 像dls说的拿拓扑和parent树一套就能出出来了... 另外表示BZOJ Rank1 tql... 暴力的话,由每个\(A_i\)向它 ...
- 洛谷P5284 [十二省联考2019]字符串问题 [后缀树]
传送门 思路 设\(dp_i\)表示以\(i\)结尾的\(A\)串,能达到的最长长度. 然后发现这显然可以\(i\)往自己控制的\(k\)连边,\(k\)往能匹配的\(j\)连边,就是个最长路,只要建 ...
- BZOJ 5496: [2019省队联测]字符串问题 (后缀数组+主席树优化建图+拓扑排序)
题意 略 分析 考场上写了暴力建图40分溜了-(结果只得了30分) 然后只要优化建边就行了 首先给出的支配关系无法优化,就直接A向它支配的B连边. 考虑B向以B作为前缀的所有A连边,做一遍后缀数组,两 ...
- 【BZOJ5496】[十二省联考2019]字符串问题(后缀树)
[BZOJ5496][十二省联考2019]字符串问题(后缀树) 题面 BZOJ 洛谷 题解 首先显然可以把具有支配关系的串从\(A\)到\(B\)连一条有向边,如果\(B_i\)是\(A_j\)的前缀 ...
- 【BZOJ5495】[十二省联考2019]异或粽子(主席树,贪心)
[BZOJ5495][十二省联考2019]异或粽子(主席树,贪心) 题面 BZOJ 洛谷 题解 这不是送分题吗... 转异或前缀和,构建可持久化\(Trie\). 然后拿一个堆维护每次的最大值,每次如 ...
- P5284 [十二省联考2019]字符串问题
这是一道涵盖了字符串.图论.数据结构三个方面的综合大题. 把这道题放在D1T2的人应该拖出去打 前置芝士 首先,您至少要会topsort. 其次,如果您只想拿个暴力分,字符串Hash就足够了:如果您想 ...
- Luogu P5284 [十二省联考2019]字符串问题
好难写的字符串+数据结构问题,写+调了一下午的说 首先理解题意后我们对问题进行转化,对于每个字符串我们用一个点来代表它们,其中\(A\)类串的点权为它们的长度,\(B\)类串的权值为\(0\) 这样我 ...
- [LOJ3049] [十二省联考 2019] 字符串问题
题目链接 LOJ:https://loj.ac/problem/3049 洛谷:https://www.luogu.org/problemnew/show/P5284 BZOJ:https://www ...
- LOJ3049 [十二省联考2019] 字符串问题 【后缀自动机】【倍增】【拓扑排序】
题目分析: 建出后缀自动机,然后把A串用倍增定位到后缀自动机上,再把B串用倍增定位到后缀自动机上. SAM上每个点上的A串根据长度从小到大排序,建点,依次连边. 再对于SAM上面每个点,连到儿子的边, ...
随机推荐
- npm run dev 启动错误:Module build failed: Error: No PostCSS Config found in:xxxxxxxxxxxxxx
解决办法:在根目录新建postcss.config.js module.exports = { plugins: { 'autoprefixer': {browsers: 'last 5 versio ...
- Java实现登录验证码
登录验证码 Servlet /* 从请求中获取数据,获取验证码的session的值转为String类型, 销毁,防止返回后验证码不刷新,重新验证成功 判断验证码是否相同(忽略大 ...
- Android为TV端助力 完全解析模拟遥控器按键
public class VirturlKeyPadCtr { private static Instrumentation mInstrumentation; public static void ...
- linux c ---raise 使用范例的代码
把做工程过程中比较好的代码片段收藏起来,下面代码内容是关于linux c ---raise 使用范例的代码,希望对各位有所用途. #include <sys/types.h> #inclu ...
- Docker for Win10中文乱码问题
environment:win10 docker+centos7+nginx1.9.9 issue:在docker运行nginx(centos),volume本地html目录挂载到nginx的htm ...
- 高版本Sqlserver数据库导入低版本Sqlserver
今天想跑一个关于java网站的demo,结果在附加数据库项这一块出现问题,例程的数据库用的是sqlserver2014,而我的是2008,添加数据库出现错误.经过一番查找,也找到某人写的一些博客上的解 ...
- CentOS编译安装PHP常见错误及解决办法
1.configure: error: No curses/termcap library found yum -y install ncurses-devel 2.configure: error: ...
- 我超级推荐的Navicat Premium 12的下载,破解方法
今天给大家推荐一款炒鸡好用的数据库管理工具,使用它,可以很方便的连接各种主流数据库软件----Navicat Premium 12 但是,它是要钱的,不过我们可以使用破解机来破解它,步骤稍有些复杂,简 ...
- 环形链表得golang实现
给定一个链表,判断链表中是否有环. 为了表示给定链表中的环,我们使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始). 如果 pos 是 -1,则在该链表中没有环. 输入:head = ...
- web框架。Django--
一,DIY一个web框架 1.1什么是web框架 1.2用socket模拟B-S的服务端 1.3,浏览器端的network查看 1.4,request格式 1.5,response格式 1.6,初识w ...