【题解】Luogu P5284 [十二省联考2019]字符串问题
原题传送门
我用sa做的本题 (码量似乎有点大)
先对原串建sa
考虑如何建图:
一开始每个以某个后缀都单独用一个链表存储。用merge函数依次将lcp为n~1的后缀的链表合并,当这个lcp为某个a串时候,在链表中插入a。当这个lcp为某个b串时候,以b开始的后缀所在的链表中的元素就是其所对应的a串(见merging函数)
现在每个b对应的a的编号都是链表中一段连续的区间
珂以用线段树优化建图
最后跑一下拓扑排序即可得出答案
#include <bits/stdc++.h>
#define N 1000005
#define M 16000005
#define ll long long
using namespace std;
inline int read()
{
register int x=0,f=1;register char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9')x=(x<<3)+(x<<1)+ch-'0',ch=getchar();
return x*f;
}
inline void write(register ll x)
{
if(!x)putchar('0');if(x<0)x=-x,putchar('-');
static int sta[20];register int tot=0;
while(x)sta[tot++]=x%10,x/=10;
while(tot)putchar(sta[--tot]+48);
}
inline ll Max(register ll a,register ll b)
{
return a>b?a:b;
}
struct edge{
int to,next;
}e[M];
int head[N],cnte=1,degree[N],w[N],nt;
inline void add_edge(register int u,register int v)
{
e[++cnte]=(edge){v,head[u]};
head[u]=cnte;
++degree[v];
}
inline void cleargraph()
{
memset(w,0,sizeof(w));
memset(degree,0,sizeof(degree));
memset(head,0,sizeof(head));
cnte=1;
}
ll dp[N];
int q[N],qh,qt;
inline ll topsort()
{
qh=qt=0;
memset(dp,0,sizeof(dp));
for(register int i=1;i<=nt;++i)
if(!degree[i])
q[++qt]=i;
ll ans=0;
while(qh<qt)
{
int u=q[++qh];
dp[u]+=w[u];
ans=Max(ans,dp[u]);
for(register int i=head[u];i;i=e[i].next)
{
int v=e[i].to;
dp[v]=Max(dp[v],dp[u]);
if(!--degree[v])
q[++qt]=v;
}
}
return qt<nt?-1LL:ans;
}
int n,sizem;
char s[N];
int rak[N],sa[N],tp[N],tex[N],height[N];
inline void Qsort()
{
for(register int i=0;i<=sizem;++i)
tex[i]=0;
for(register int i=1;i<=n;++i)
++tex[rak[i]];
for(register int i=1;i<=sizem;++i)
tex[i]+=tex[i-1];
for(register int i=n;i>=1;--i)
sa[tex[rak[tp[i]]]--]=tp[i];
}
inline void sa_build()
{
memset(tp,0,sizeof(tp));
memset(rak,0,sizeof(rak));
sizem=30;
for(register int i=1;i<=n;++i)
rak[i]=s[i]-'a'+1,tp[i]=i;
Qsort();
for(register int w=1,p=0;p<n;sizem=p,w<<=1)
{
p=0;
for(register int i=1;i<=w;++i)
tp[++p]=n-w+i;
for(register int i=1;i<=n;++i)
if(sa[i]>w)
tp[++p]=sa[i]-w;
Qsort();
swap(tp,rak);
rak[sa[1]]=p=1;
for(register int i=2;i<=n;++i)
rak[sa[i]]=(tp[sa[i-1]]==tp[sa[i]]&&tp[sa[i-1]+w]==tp[sa[i]+w])?p:++p;
}
}
inline void getheight()
{
int k=0;
for(register int i=1;i<=n;++i)
{
if(k)
--k;
int j=sa[rak[i]-1];
while(s[i+k]==s[j+k])
++k;
height[rak[i]]=k;
}
}
struct Unionset{
int f[N];
inline void makeset(register int n)
{
for(register int i=1;i<=n;++i)
f[i]=i;
}
inline int find(register int x)
{
return f[x]==x?f[x]:f[x]=find(f[x]);
}
inline void merge(register int x,register int y)
{
if(find(x)!=find(y))
f[f[x]]=f[y];
}
};
struct ListNode{
int l,r;
ListNode():l(-1),r(-1){}
};
ListNode* listNode=nullptr;
inline void clearListNodes()
{
if(listNode!=nullptr)
delete[] listNode;
listNode=new ListNode[N];
}
struct List{
int head,tail;
List():head(-1),tail(-1){}
List(int node):head(node),tail(node){}
List(int l,int r):head(l),tail(r){}
List operator +(const List& other){
if(tail==-1)
return other;
if(other.head==-1)
return *this;
listNode[tail].r=other.head;
listNode[other.head].l=tail;
return List(head,other.tail);
}
};
int na,nb,la[N],ra[N],lb[N],rb[N];
List lst[N];
vector<int> merges[N],alen[N],blen[N];
Unionset us;
int invl[N],invr[N],ppos[N],seq[N];
inline void merging()
{
clearListNodes();
for(register int i=1;i<=n;++i)
lst[i]=List();
for(register int i=0;i<=n;++i)
{
merges[i].clear();
alen[i].clear();
blen[i].clear();
}
for(register int i=1;i<n;++i)
merges[height[i+1]].push_back(i);
for(register int i=1;i<=na;++i)
alen[ra[i]-la[i]+1].push_back(i);
for(register int i=1;i<=nb;++i)
blen[rb[i]-lb[i]+1].push_back(i);
us.makeset(n);
for(register int len=n;len>=0;--len)
{
for(register int i=0;i<merges[len].size();++i)
{
int k=merges[len][i];
int u=us.find(k),v=us.find(k+1);
List tmp=lst[u]+lst[v];
us.merge(u,v);
lst[us.find(u)]=tmp;
}
for(register int i=0;i<alen[len].size();++i)
{
int a=alen[len][i];
int u=us.find(rak[la[a]]);
lst[u]=List(a)+lst[u];
}
for(register int i=0;i<blen[len].size();++i)
{
int b=blen[len][i];
int v=us.find(rak[lb[b]]);
invl[b]=Max(0,lst[v].head);
invr[b]=Max(0,lst[v].tail);
}
}
for(register int i=1,u=lst[us.find(1)].head;i<=na;++i,u=listNode[u].r)
{
if(u==-1)
break;
seq[i]=u;
ppos[u]=i;
}
ppos[0]=-1;
for(register int i=1;i<=nb;++i)
{
invl[i]=ppos[invl[i]];
invr[i]=ppos[invr[i]];
}
}
inline void input()
{
scanf("%s",s+1);
n=strlen(s+1);
na=read();
for(register int i=1;i<=na;++i)
la[i]=read(),ra[i]=read();
nb=read();
for(register int i=1;i<=nb;++i)
lb[i]=read(),rb[i]=read();
cleargraph();
int m=read();
for(register int i=1;i<=m;++i)
{
int x=read(),y=read();
add_edge(x,na+y);
}
}
int tot=0,ls[N],rs[N];
inline void seg_build(register int &x,register int l,register int r)
{
if(l==r)
{
x=seq[l];
return;
}
else
x=++tot;
int mid=l+r>>1;
seg_build(ls[x],l,mid);
seg_build(rs[x],mid+1,r);
add_edge(x,ls[x]),add_edge(x,rs[x]);
}
inline void seg_addedge(register int x,register int l,register int r,register int b,register int L,register int R)
{
if(L<=l&&r<=R)
{
add_edge(b+na,x);
return;
}
int mid=l+r>>1;
if(L<=mid)
seg_addedge(ls[x],l,mid,b,L,R);
if(R>mid)
seg_addedge(rs[x],mid+1,r,b,L,R);
}
inline void buildsegtr()
{
tot=na+nb;
int root;
seg_build(root,1,na);
for(register int i=1;i<=nb;++i)
{
if(invl[i]<0)
continue;
seg_addedge(root,1,na,i,invl[i],invr[i]);
}
nt=tot;
}
inline ll solve()
{
input();
sa_build();
getheight();
merging();
buildsegtr();
for(register int i=1;i<=na;++i)
w[i]=ra[i]-la[i]+1;
return topsort();
}
int T;
int main()
{
T=read();
while(T--)
write(solve()),puts("");
return 0;
}
【题解】Luogu P5284 [十二省联考2019]字符串问题的更多相关文章
- Luogu P5284 [十二省联考2019]字符串问题
好难写的字符串+数据结构问题,写+调了一下午的说 首先理解题意后我们对问题进行转化,对于每个字符串我们用一个点来代表它们,其中\(A\)类串的点权为它们的长度,\(B\)类串的权值为\(0\) 这样我 ...
- P5284 [十二省联考2019]字符串问题
这是一道涵盖了字符串.图论.数据结构三个方面的综合大题. 把这道题放在D1T2的人应该拖出去打 前置芝士 首先,您至少要会topsort. 其次,如果您只想拿个暴力分,字符串Hash就足够了:如果您想 ...
- 洛谷P5284 [十二省联考2019]字符串问题(SAM+倍增+最长路)
题面 传送门 题解 首先,我们把串反过来,那么前缀就变成后缀,建一个\(SAM\).我们发现一个节点的后缀是它的所有祖先 那么我们是不是直接按着\(parent\)树建边就可以了呢? 显然不是.我们假 ...
- 洛谷P5284 [十二省联考2019]字符串问题 [后缀树]
传送门 思路 设\(dp_i\)表示以\(i\)结尾的\(A\)串,能达到的最长长度. 然后发现这显然可以\(i\)往自己控制的\(k\)连边,\(k\)往能匹配的\(j\)连边,就是个最长路,只要建 ...
- 【BZOJ5496】[十二省联考2019]字符串问题(后缀树)
[BZOJ5496][十二省联考2019]字符串问题(后缀树) 题面 BZOJ 洛谷 题解 首先显然可以把具有支配关系的串从\(A\)到\(B\)连一条有向边,如果\(B_i\)是\(A_j\)的前缀 ...
- [十二省联考2019]字符串问题——后缀自动机+parent树优化建图+拓扑序DP+倍增
题目链接: [十二省联考2019]字符串问题 首先考虑最暴力的做法就是对于每个$B$串存一下它是哪些$A$串的前缀,然后按每组支配关系连边,做一遍拓扑序DP即可. 但即使忽略判断前缀的时间,光是连边的 ...
- 【题解】Luogu P5291 [十二省联考2019]希望
ytq鸽鸽出的题真是毒瘤 原题传送门 题目大意: 有一棵有\(n\)个点的树,求有多少方案选\(k\)个联通块使得存在一个中心点\(p\),所有\(k\)个联通块中所有点到\(p\)的距离都\(\le ...
- 【题解】Luogu P5283 [十二省联考2019]异或粽子
原题传送门 看见一段的异或和不难想到要做异或前缀和\(s\) 我们便将问题转化成:给定\(n\)个数,求异或值最靠前的\(k\)对之和 我们珂以建一个可持久化01trie,这样我们就珂以求出每个值\( ...
- 【题解】Luogu P5290 [十二省联考2019]春节十二响
原题传送门 每个点维护一个堆,表示这个点及其子树所需的每段内存的空间 搜索时从下向上做启发式合并堆中信息,最后根节点堆中所有内存空间之和就是答案 #include <bits/stdc++.h& ...
随机推荐
- 电子产品使用感受之——为什么我那么喜欢2015年的11.6寸MacBook Air?
2018年Mac笔记本产品线得到了一次更新,Mac book Pro, MacBook Air更新后的Mac 产品线变得更加让人摸不着头脑,价格昂贵不说,产品分类细化到如此程度,让一个选择困难症的消费 ...
- F#周报2019年第16期
新闻 Ionide试验版本 FSharp路线图介绍 Blazor官方预览 .NET Framework 4.8发布 .NET Core 3 Preview 4发布 需要来自FSharp.Data.Sq ...
- F#周报2019年第12期
新闻 Amazon.Lambda.RuntimeSupport发布 Forge 3.0架构 Blazor 0.9.0试验版发布 通过微软游戏栈实现更多应用 介绍ASP.NET Core中的gRPC M ...
- 对SDE中空要素类插入要素,完成后显示的图层特别小
原因是缺少图层Extent或者Extent发生变化,插入完成后需要对图层的Extent进行更新. 调用IFeatureClassManage. UpdateExtent更新范围 参考链接: https ...
- 【转载】Fiddler工具使用介绍(一)
原文https://www.cnblogs.com/miantest/p/7289694.html(一) https://www.cnblogs.com/miantest/p/7290176.html ...
- jmeter 之 beanshell sample
Lightweight Scripting for Java 官网:http://www.BeanShell.org/ 定时器: BeanShell Timer 前置处理器:BeanShell Pre ...
- div盒子水平居垂直中的几种方法
div盒子水平居垂直中的几种方法<!DOCTYPE html><html> <head> <mete charset="ut ...
- U盘挂载指令
相关步骤来自于百度 1.先确定U盘格式,如果是ntfs格式,需要先安装3g-ntfs这个软件支持ntfs格式,以下默认U盘为fat32格式 2.使用fdisk -l 查看分区表,找到u盘的设备号,比如 ...
- 3.远程连接工具、JDK安装
1.实现Centos和windows的文件传输,可以使用Xshell和Xftp(实验指导使用的是winscp). (1).可以使用Xshell远程登陆Linux,具体安装过程略. (2).登陆Cent ...
- 04.常量变量和数据类型(const)
1.关键字 2.数据类型 告诉编译器定义一个类型变量的空间! 3.常量 4.变量 在程序运行过程中,值可以改变 变量在使用前必须先定义,定义变量前必须有相应的数据类型 标识符命名规则: (1).标识符 ...