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

首先理解题意后我们对问题进行转化,对于每个字符串我们用一个点来代表它们,其中\(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. D. Kuro and GCD and XOR and SUM

    Kuro is currently playing an educational game about numbers. The game focuses on the greatest common ...

  2. DCOS实践分享(4):如何基于DC/OS整合SMACK(Spark, Mesos, Akka, Cassandra, Kafka)

    这篇文章入选CSDN极客头条 http://geek.csdn.net/news/detail/71572 当前,要保证业务的市场竞争力,仅靠设计一个可用并且好看的产品,已经完全不能满足要求.全球消费 ...

  3. nodejs模板加载的问题

    JADE模板:http://jumplink.github.io/jade2html2jade/ HTML转JADE,跟imooc上一步步来就搞定了 直接加载HTML静态资源: var express ...

  4. 关于Random(47)与randon.nextInt(100)的区别

    参考https://blog.csdn.net/md_shmily92/article/details/44059313 相关文章random.nextInt()与Math.random()基础用法 ...

  5. Oracle中的decode()函数

    一.decode()函数 1.语法 DECODE(control_value,value1,result1[,value2,result2-][,default_result]); control _ ...

  6. centos7系统服务管理

    systemd是RH7系列操作系统开始启用新的系统和服务管理器.它被设计为与sysv init脚本向后兼容,并提供了一些功能,例如在引导时并行启动系统服务,按需激活守护程序或基于依赖关系的服务控制逻辑 ...

  7. Solr相似性算法

    Solr相似性算法 介绍 Solr 4及之前的版本默认采用VSM(向量空间模型)进行相似度的计算(或打分).之后的版本,则采用Okapi BM25(一种二元独立模型的扩展),属于概率模型. 检索模型通 ...

  8. python3——模块

    今天去听一个关于创业的讲座,心疼自己在那个地方站了 一个多小时(QAQ)我是心疼自己傻呀! 手机打王者之后就没有电了,一直站在那儿! 不过最后还是结束了,以后你们也会有很多讲座的,希望学弟学妹好好听讲 ...

  9. 并发的核心:CAS 是什么?Java8是如何优化 CAS 的?

    大家可能都听说说 Java 中的并发包,如果想要读懂 Java 中的并发包,其核心就是要先读懂 CAS 机制,因为 CAS 可以说是并发包的底层实现原理. 今天就带大家读懂 CAS 是如何保证操作的原 ...

  10. 深入理解java虚拟机之java内存区域

    java虚拟机在执行java程序的时候会把它所管理的内存分为多个不同的区域,每个区域都有不同的作用,以及由各自的生命周期,有些随着虚拟机进行的启动而存在,有些区域则依赖于用户线程的启动或结束而建立或销 ...