好难写的字符串+数据结构问题,写+调了一下午的说

首先理解题意后我们对问题进行转化,对于每个字符串我们用一个点来代表它们,其中\(A\)类串的点权为它们的长度,\(B\)类串的权值为\(0\)

这样我们根据题意把\(A\to B\)的边连起来,同时每个\(B\)类串向所有以其为前缀的\(A\)类串连边

这样我们就得到了一张DAG(如果不是的话就输出\(-1\)),然后对于它拓扑排序之后求权值和最大链即可

但是第二类边该怎么连呢,下面我们来分析一下具体操作


SA转化问题

首先关于这种前后缀相关的问题,我们大可以利用SA来搞

先对于原串建出SA,然后对于每一个\(B\)类串\(b_i\),我们找到\(rk_{lb_{b_i}}\),然后二分向两边扩展找出与它\(\operatorname{LCP}\ge len_{b_i}\)的最大区间(可利用关于\(\operatorname{LCP}\)的定理证明单调性)

然后我们直接从这个\(B\)类串向找到的区间连边?所以直接一发线段树优化建图就OK了?

但是有一个问题,就是SA上的后缀长度和实际长度不相等,所以可能会出现\(|A<|B|\)的情况,此时显然\(B\)不能算作\(A\)的前缀

所以我们要请出一个全新的技巧——主席树优化建图


主席树优化建图

由于这里最难处理的还是字符串长度,所以我们以此为版本建立主席树

\(A\)类串的处理比较简单,我们可以直接从它对应版本对应\(rk\)的点向它连边

然后对于\(B\)类串,向对应版本的区间连边,同时为了使复杂度不爆炸我们从父节点向子节点连边,这样区间连边的复杂度就是\(\log n\)级别的

然后对于主席树之间,我们从小到大连边,这样就保证了只能向长度更大的串走

所以这道题顺利完成了


复杂度分析

首先由于这题中的各种东西都可以认为与\(N\)同阶,那么:

总点数:\(n+n\log n\);总边数:\(2n+4n\log n\);总复杂度:\(O(T\cdot n\log n)\)

CODE

#include<cstdio>
#include<cctype>
#include<vector>
#include<cstring>
#include<iostream>
#define RI register int
#define CI const int&
#define Tp template <typename T>
#define Ms(f,x) memset(f,x,sizeof(f))
using namespace std;
typedef long long LL;
const int N=2e5+5,P=20,AN=(N<<1)+N*P,AM=(N<<1)+(N*P<<2);
struct edge
{
int to,nxt;
}e[AM]; int head[AN],cnt,tot,x,y; vector <int> v[N];
char s[N]; int t,m,len,na,nb,la[N],ra[N],lb[N],rb[N];
int deg[AN],rt[N],rt_[N],q[AN],val[AN]; long long f[AN];
inline void add(CI x,CI y)
{
if (!y) return; e[++cnt]=(edge){y,head[x]}; head[x]=cnt; ++deg[y];
}
class President_Tree
{
private:
int ch[AN][2],cur;
inline int insert(CI lst,int &now,CI pos,CI l=1,CI r=len)
{
now=++tot; ch[tot][0]=ch[lst][0]; ch[tot][1]=ch[lst][1];
add(now,lst); if (l==r) return now; int mid=l+r>>1,id;
if (pos<=mid) id=insert(ch[lst][0],ch[now][0],pos,l,mid);
else id=insert(ch[lst][1],ch[now][1],pos,mid+1,r);
add(now,ch[now][0]); add(now,ch[now][1]); return id;
}
public:
inline void clear(void)
{
for (RI i=1;i<=tot;++i) ch[i][0]=ch[i][1]=0; tot=cur=0;
}
inline int insert(CI len,CI pos)
{
++cur; int id=insert(rt_[cur-1],rt_[cur],pos); rt[len]=rt_[cur]; return id;
}
#define O num,beg,end
inline void link(CI now,CI num,CI beg,CI end,CI l=1,CI r=len)
{
if (!now) return; if (beg<=l&&r<=end) return add(num,now); int mid=l+r>>1;
if (beg<=mid) link(ch[now][0],O,l,mid); if (end>mid) link(ch[now][1],O,mid+1,r);
}
#undef O
}SEG;
class Suffix_Array
{
private:
int sa[N],t[N],bkt[N],hgt[N],log[N],f[N][P],size;
inline void Radix_Sort(CI n)
{
RI i; for (i=0;i<=size;++i) bkt[i]=0;
for (i=1;i<=n;++i) ++bkt[rk[i]];
for (i=1;i<=size;++i) bkt[i]+=bkt[i-1];
for (i=n;i;--i) sa[bkt[rk[t[i]]]--]=t[i];
}
inline void build(char *s,CI n)
{
RI i; for (size=122,i=1;i<=n;++i) rk[i]=s[i],t[i]=i;
Radix_Sort(n); for (RI w=1,p=1;p<n;size=p,w<<=1)
{
for (p=0,i=n-w+1;i<=n;++i) t[++p]=i;
for (i=1;i<=n;++i) if (sa[i]>w) t[++p]=sa[i]-w;
Radix_Sort(n); swap(rk,t); rk[sa[1]]=p=1;
for (i=2;i<=n;++i) rk[sa[i]]=(t[sa[i-1]]==t[sa[i]]&&t[sa[i-1]+w]==t[sa[i]+w])?p:++p;
}
}
inline void get_height(char *s,CI n)
{
RI i,lst=0; for (i=1;i<=n;++i) rk[sa[i]]=i;
for (i=1;i<=n;++i)
{
if (rk[i]==1) continue; if (lst) --lst; int pos=sa[rk[i]-1];
while (pos+lst<=n&&i+lst<=n&&s[pos+lst]==s[i+lst]) ++lst; hgt[rk[i]]=lst;
}
}
inline int min(CI a,CI b)
{
return a<b?a:b;
}
inline int LCP(int x,int y)
{
if (x>y) swap(x,y); ++x; int k=log[y-x+1];
return min(f[x][k],f[y-(1<<k)+1][k]);
}
public:
int rk[N];
inline void init(char *s,CI n)
{
RI i; build(s,n); get_height(s,n);
for (log[0]=-1,i=1;i<=n;++i) log[i]=log[i>>1]+1;
for (i=1;i<=n;++i) f[i][0]=hgt[i];
for (RI j=1;j<P;++j) for (i=1;i+(1<<j)-1<=n;++i)
f[i][j]=min(f[i][j-1],f[i+(1<<j-1)][j-1]);
}
inline void work(CI id)
{
int pos=rk[lb[id]],l,r,mid,nl=rb[id]-lb[id]+1,ret1=pos,ret2=pos;
l=1; r=pos-1; while (l<=r) if (LCP(mid=l+r>>1,pos)>=nl) ret1=mid,r=mid-1; else l=mid+1;
l=pos+1; r=len; while (l<=r) if (LCP(mid=l+r>>1,pos)>=nl) ret2=mid,l=mid+1; else r=mid-1;
SEG.link(rt[nl],na+id,ret1,ret2);
}
}SA;
inline void maxer(LL& x,const LL& y)
{
if (y>x) x=y;
}
#define to e[i].to
inline LL Topo_Sort(LL ans=0)
{
RI H=0,T=0,i; for (i=1;i<=na;++i) f[i]=val[i]=ra[i]-la[i]+1;
for (i=1;i<=tot;++i) if (!deg[i]) q[++T]=i; while (H<T)
{
int now=q[++H]; for (maxer(ans,f[now]),i=head[now];i;i=e[i].nxt)
if (maxer(f[to],f[now]+val[to]),!--deg[to]) q[++T]=to;
}
return T!=tot?-1:ans;
}
#undef to
inline void solve(void)
{
RI i; scanf("%s",s+1); len=strlen(s+1); SA.init(s,len);
for (scanf("%d",&na),i=1;i<=na;++i)
scanf("%d%d",&la[i],&ra[i]),v[ra[i]-la[i]+1].push_back(i);
for (scanf("%d",&nb),i=1;i<=nb;++i) scanf("%d%d",&lb[i],&rb[i]);
for (tot=na+nb,i=len;i;--i)
{
rt[i]=rt[i+1]; for (int it:v[i])
add(SEG.insert(i,SA.rk[la[it]]),it);
}
for (i=1;i<=nb;++i) SA.work(i); for (scanf("%d",&m),i=1;i<=m;++i)
scanf("%d%d",&x,&y),add(x,na+y); printf("%lld\n",Topo_Sort());
}
inline void clear(void)
{
cnt=0; Ms(head,0); Ms(deg,0); SEG.clear(); Ms(f,0); Ms(val,0);
for (RI i=1;i<=len;++i) rt[i]=rt_[i]=0,v[i].clear();
}
int main()
{
//freopen("CODE.in","r",stdin); freopen("CODE.out","w",stdout);
for (scanf("%d",&t);t;--t) solve(),clear(); return 0;
}

Luogu P5284 [十二省联考2019]字符串问题的更多相关文章

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

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

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

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

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

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

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

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

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

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

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

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

  7. Luogu P5285 [十二省联考2019]骗分过样例

    Preface ZJOI一轮被麻将劝退的老年选手看到这题就两眼放光,省选也有乱搞题? 然后狂肝了3~4天终于打完了,期间还补了一堆姿势 由于我压缩技术比较菜,所以用的都是非打表算法,所以一共写了5K- ...

  8. luogu P5291 [十二省联考2019]希望

    luogu loj 无论最终结果将人类历史导向何处 \(\quad\)我们选择 \(\quad\quad\)\(\large{希望}\) 诶我跟你讲,这题超修咸的 下面称离连通块内每个点距离不超过\( ...

  9. Luogu P5290 [十二省联考2019]春节十二响

    这题是最近看到的今年省选题中最良心的一道了吧 看题+想题+写题都可以在0.5h内解决,送分含义明显啊 首先理解了题意后我们很快就能发现两个点如果要被分在一段那么必须在它们的祖先处合并 首先我们考虑下二 ...

随机推荐

  1. capwap学习笔记——capwap的前世今生(转)

    1 capwap的前世今生 1.1 胖AP.瘦AP.AC 传统的WLAN网络都是为企业或家庭内少量移动用户的接入而组建的.因此,只需要一个无线路由器就可以搞定了,就好像现在家用的无线路由器就是胖AP. ...

  2. 2018-05-17-OAA-一种mermaid脚本驱动的软件项目模块图形化表述思路

    layout: post title: 2018-05-17-OAA-一种mermaid脚本驱动的软件项目模块图形化表述思路 key: 20180517 tags: OAA flow chart se ...

  3. rsyslog & syslog详解

    前言: rsyslog 是一个 syslogd 的多线程增强版.syslog是Linux系统默认的日志守护进程.默认的syslog配置文件是/etc/syslog.conf文件.程序,守护进程和内核提 ...

  4. JAVA PERSISTENCE API (JPA)

    13.2.1. About JPA The Java Persistence API (JPA) is the standard for using persistence in Java proje ...

  5. pymysql安装

    安装python3之后 链接数据库需要安装pymysql pymysql 下载地址 https://pypi.python.org/pypi/PyMySQL3/0.5 ,下载之后传到linux虚拟机, ...

  6. tkinter中frame布局控件(九)

    frame控件 frame控件是将窗口分成好几个小模块,然后每个小模块中添加控件. 也就是将窗口合理的布局 由于和其他控件的操作基本一致,就不做注释了 import tkinter wuya = tk ...

  7. C/C++中结构体struct 的使用

    结构(struct)      结构是由基本数据类型构成的.并用一个标识符来命名的各种变量的组合.  结构中可以使用不同的数据类型.      1. 结构说明和结构变量定义      在Turbo C ...

  8. LNMP单点服务器搭建

    一.部署服务器环境 Linux:centos6.5 nginx:1.14.0 mysql:5.6.33 php:5.6.36 1.网络配置 2.FQDN /etc/hosts /etc/sysconf ...

  9. ResultSet,RowSet,OracleCachedRowSet和RowSetMetaData区别及联系

    在java主要涉及到数据开发的过程中,我们会和数据库打交道很多,其中使用了数据集比如ResultSet和RowSet,经常使用两种,还有其它的一些,那么这两种的主要区别是什么呢?我们先来看它们引入的方 ...

  10. SDOI2017 BZOJ 4820 硬币游戏 解题报告

    写在前面 此题网上存在大量题解,但本人太菜了,看了不下10篇均未看懂,只好自己冷静分析了.本文将严格详细地论述算法(避免一切意会和玄学),因此可能会比其它题解更加理论化一些,希望能对像我一样看了其它题 ...