Luogu P5284 [十二省联考2019]字符串问题
好难写的字符串+数据结构问题,写+调了一下午的说
首先理解题意后我们对问题进行转化,对于每个字符串我们用一个点来代表它们,其中\(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]字符串问题的更多相关文章
- 【题解】Luogu P5284 [十二省联考2019]字符串问题
原题传送门 我用sa做的本题 (码量似乎有点大) 先对原串建sa 考虑如何建图: 从大到小枚举长度len 先将height中等于len的两个位置在并查集合并起来,将lst也合并(lst是链表) 再将长 ...
- P5284 [十二省联考2019]字符串问题
这是一道涵盖了字符串.图论.数据结构三个方面的综合大题. 把这道题放在D1T2的人应该拖出去打 前置芝士 首先,您至少要会topsort. 其次,如果您只想拿个暴力分,字符串Hash就足够了:如果您想 ...
- 洛谷P5284 [十二省联考2019]字符串问题 [后缀树]
传送门 思路 设\(dp_i\)表示以\(i\)结尾的\(A\)串,能达到的最长长度. 然后发现这显然可以\(i\)往自己控制的\(k\)连边,\(k\)往能匹配的\(j\)连边,就是个最长路,只要建 ...
- 洛谷P5284 [十二省联考2019]字符串问题(SAM+倍增+最长路)
题面 传送门 题解 首先,我们把串反过来,那么前缀就变成后缀,建一个\(SAM\).我们发现一个节点的后缀是它的所有祖先 那么我们是不是直接按着\(parent\)树建边就可以了呢? 显然不是.我们假 ...
- [十二省联考2019]字符串问题——后缀自动机+parent树优化建图+拓扑序DP+倍增
题目链接: [十二省联考2019]字符串问题 首先考虑最暴力的做法就是对于每个$B$串存一下它是哪些$A$串的前缀,然后按每组支配关系连边,做一遍拓扑序DP即可. 但即使忽略判断前缀的时间,光是连边的 ...
- 【BZOJ5496】[十二省联考2019]字符串问题(后缀树)
[BZOJ5496][十二省联考2019]字符串问题(后缀树) 题面 BZOJ 洛谷 题解 首先显然可以把具有支配关系的串从\(A\)到\(B\)连一条有向边,如果\(B_i\)是\(A_j\)的前缀 ...
- Luogu P5285 [十二省联考2019]骗分过样例
Preface ZJOI一轮被麻将劝退的老年选手看到这题就两眼放光,省选也有乱搞题? 然后狂肝了3~4天终于打完了,期间还补了一堆姿势 由于我压缩技术比较菜,所以用的都是非打表算法,所以一共写了5K- ...
- luogu P5291 [十二省联考2019]希望
luogu loj 无论最终结果将人类历史导向何处 \(\quad\)我们选择 \(\quad\quad\)\(\large{希望}\) 诶我跟你讲,这题超修咸的 下面称离连通块内每个点距离不超过\( ...
- Luogu P5290 [十二省联考2019]春节十二响
这题是最近看到的今年省选题中最良心的一道了吧 看题+想题+写题都可以在0.5h内解决,送分含义明显啊 首先理解了题意后我们很快就能发现两个点如果要被分在一段那么必须在它们的祖先处合并 首先我们考虑下二 ...
随机推荐
- Oracle-12:伪列rowid和rownum
------------吾亦无他,唯手熟尔,谦卑若愚,好学若饥------------- 伪列:不真实存储在真表中,但是我们可以查询到不能对伪列进行增删改操作! 分页可以用rownum来分!!!!!! ...
- C++关于Union使用的部分总结
说明:未加说明,struct均指C++语言中的struct(可以有成员函数,可以定义访问属性) 1 什么是Union? (1)与class,struct相似用于定义数据结构:union 可以说是一种特 ...
- eclipse如何新建项目发布到git
1.首先去查询本地git仓库地址 2.找到项目位置 删除git版本 3.更换git提交目标地址 目标地址是新建的git仓库地址 4.提交
- sql server按符号截取字符串
http://www.360doc.com/content/12/0626/13/1912775_220523992.shtml
- jQuery.on() 函数详解 【转载】
注意事项 1:on()为指定元素的一个或多个事件绑定事件处理函数.(可传递参数) 2:从jQuery 1.7开始,on()函数提供了绑定事件处理程序所需的所有功能,用于统一取代以前的bind(). d ...
- angularJS--apply() 、digest()和watch()方法
外文网址:http://www.sitepoint.com/understanding-angulars-apply-digest/ $apply()和$digest()在AngularJS中是两个核 ...
- 11. 将博客部署到tomcat上
springboot项目既可以以jar运行,也可以做成war包放到服务器上,因为我的博客项目涉及到文件上传,所以按照jar的方式就不可行,需要部署到tomcat上,具体做法如下:1. 修改pom.xm ...
- Windows下python3和python2同时安装python2.exe、python3.exe和pip2、pip3设置
1.添加python2到系统环境变量 打开,控制面板\系统和安全\系统,选择高级系统设置,环境变量,选择Path,点击编辑,新建,分别添加D:\Python\python27和D:\Python\py ...
- Elasticsearch笔记三之版本控制和插件
版本控制 1:关系型数据库使用的是悲观锁,数据被读取后就被锁定其他的线程就无法对其进行修改. 2:ex使用的是乐观锁,数据被读取后其他程序还可以对其进行修改,而执行修改时发现此数据已经被修改则修改就会 ...
- ANSI 和 UNICODE 的函数对应表
ANSI UNICODE 通用(char.h) (wchar.h) (tchar.h) char wchar_t ...