【题解】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& ...
随机推荐
- css学习_cs3s旋转的图片
1. ,鼠标移开后图片面向屏幕后又自动可见了. 2.css3动画 !!定义好动画后再引用 4.多组动画(百分比) 案例: 案例2----无缝滚动
- oo第二单元作业总结
oo第二单元博客总结 在第一单元求导结束后,迎来了第二单元的多线程电梯的问题,在本单元前两次作业中个人主要应用两个线程,采用“生产者-消费者”模式和共享数据变量的方式解决问题.在第三次作业中加入多个电 ...
- Express全系列教程之(五):Express的中间件
一.中间件 从字面意思,我们可以了解到它大概就是做中间代理操作,事实也是如此:大多数情况下,中间件就是在做接收到请求和发送响应中间的一系列操作.事实上,express是一个路由和中间件的web框架,E ...
- Mac OSX bash function 备份
# mount the android file image function mountAndroid { hdiutil attach ~/android.dmg.sparsefile.spars ...
- Mac上安装Charles进行抓包全流程设置
安装 -- 官网下载最新版的Charles版本,按照提示安装即可 破解 -- https://blog.csdn.net/qq_25821067/article/details/79848589. M ...
- 2019/4/22 拓扑排序的高效写法. 模板题HDU1285:确定比赛名次
传送门 Problem Description 有N个比赛队(1<=N<=500),编号依次为1,2,3,....,N进行比赛,比赛结束后,裁判委员会要将所有参赛队伍从前往后依次排名,但现 ...
- 007-chrome插件系列
1.Axure RP Extension for Chrome 2.Charset 3.CLEAN crxMouse Gestures 4.Google 翻译 5.JSONView 6.restlet
- 我的FPGA之旅4---led流水灯
[1]输入端口不能使用reg数据类型,因为reg类型对应的FPGA内部的寄存器.这样理解:reg寄存器具有记忆功能;而wire类型数据就相当于一根连线.input输入信号用wire连线进来就好:out ...
- 表情的战争(App名称)技术服务支持
1.进入游戏走过场动画,可以点击退出跳过此过场动画: 2.进入主界面后直接点击开始游戏进入场景跑图,进入npc对话面板,对话结束进入战斗面板: 3.战斗操作方法为玩家拖动表情牌,进行攻击或者防守,直至 ...
- c# ASP.NET Core2.2利用中间件支持跨域请求
1.public void Configure(IApplicationBuilder app, IHostingEnvironment env)方法里面 不要加上:app.UseCors(); 2. ...