洛谷5284 十二省联考 字符串问题 SAM 倍增 拓扑排序 排序

版权声明:本文为博主原创文章,可以转载但是必须声明版权。 https://blog.csdn.net/forever_shi/article/details/89186959

题目链接

题意:
给你一个长度为 n n 的串,我们会从中选出 n a na 个子串作为 A A 集合的串,选出 n b nb 个子串作为 B B 集合的串。然后会有 m m 组支配关系,每组支配关系给你一个在 A A 集合中的子串的编号,一个在 B B 集合中的子串编号,表示如果 B B 对应的这个编号的子串是某一个 A A 中的串的前缀的话,那个 A A 中的串就可以接在当前 A A 中的串的后面。问最长能接出多长的串,如果能无限长输出 1 -1 。多组数据。所有数据范围都是 2 e 5 2e5 ,字符集大小是小写字母。

题解:
送我退役的几道题中送的最彻底的一道。考场上想出了正解,却差一个排序没写出来。

来详细的讲述一下这个题的思考过程吧。首先一个问题是,我不怎么会SA,于是拿出一个子串的话只会SAM上子串定位,那么就来考虑一下SAM能不能做。我们子串定位的时候在定位的时候每个点挂一个vector,因为这个点可能是endpos等价类相同的点可能代表多个长度不同的串,所以我们还要按照长度顺序来连接这些点。考场上就是这个地方出了问题,没写出来的。

我们要子串定位之后找串之间的前缀关系,于是我们应该去建反串,这样parent树上的父节点都是子节点在原串上前缀。我们发现我们应该建图来求最大值。我们发现其实对于一个 B B 中的串,可以以它为前缀的 A A 中的串都是子串定位后它parent树中子树的A串。

往一个子树中的连边这个过程我们要想办法优化。这个优化的方法是我们利用parent树来优化。具体来讲,我们从父节点向子节点连边。然后我们考虑同一个点的vector之内的这些点,我们要保证不同长度的 B B 连的 A A 的集合不同,反正自己想个能保证这个的写法就行了。

然后你拓扑排序一下,看看是不是有环,有环的话就可以无限长,否则就一边拓扑排序一边求个最长路就好了。

这么看来也不是那么难嘛(虽然确实不怎么难啊QAQ)。时间复杂度是 O ( n l o g n ) O(nlogn)

代码:

#include <bits/stdc++.h>
using namespace std;

int T,na,nb,n,m,cnt,rt=1,lst,fa[400010],ch[400010][26],len[400010];
int hed[400010],book[400010],f[400010][21],dep[400010],ed[800010];
int num,du[1600010],hed1[1600010],num1;
long long dis[1600010],ans,res[1600010];
char s[200010];
struct qwq
{
	int len,opt,id;
};
bool operator < (qwq x,qwq y)
{
	if(x.len==y.len)
	return x.opt>y.opt;
	return x.len>y.len;
}
vector<qwq> v[400010];
queue<int> q;
struct node
{
	int to,next;
}a[3200010],b[3200010];
inline int read()
{
	int x=0;
	char s=getchar();
	while(s>'9'||s<'0')
	s=getchar();
	while(s>='0'&&s<='9')
	{
		x=x*10+s-'0';
		s=getchar();
	}
	return x;
}
inline void insert(int x,int id)
{
	int cur=++cnt,pre=lst;
	lst=cur;
	len[cur]=len[pre]+1;
	for(;!ch[pre][x]&&pre;pre=fa[pre])
	ch[pre][x]=cur;
	if(!pre)
	fa[cur]=rt;
	else
	{
		int ji=ch[pre][x];
		if(len[ji]==len[pre]+1)
		fa[cur]=ji;
		else
		{
			int gg=++cnt;
			fa[gg]=fa[ji];
			memcpy(ch[gg],ch[ji],sizeof(ch[ji]));
			fa[ji]=fa[cur]=gg;
			len[gg]=len[pre]+1;
			for(;ch[pre][x]==ji&&pre;pre=fa[pre])
			ch[pre][x]=gg;
		}
	}
	book[id]=cur;
}
inline void add(int from,int to)
{
	a[++num].to=to;
	a[num].next=hed[from];
	hed[from]=num;
}
inline void add2(int from,int to)
{
	b[++num1].to=to;
	b[num1].next=hed1[from];
	hed1[from]=num1;
}
inline void dfs(int x)
{
	for(int i=1;i<=20;++i)
	f[x][i]=f[f[x][i-1]][i-1];
	for(int i=hed[x];i;i=a[i].next)
	{
		int y=a[i].to;
		if(y==f[x][0])
		continue;
		f[y][0]=x;
		dep[y]=dep[x]+1;
		dfs(y);
	}
}
inline int lca(int x,int y)
{
	for(int i=20;i>=0;--i)
	{
		if(f[x][i]&&len[f[x][i]]>=y)
		x=f[x][i];
	}
	return x;
}
int main()
{
	T=read();
	while(T--)
	{
		cnt=1;
		rt=1;
		lst=1;
		num=0;
		num1=0;
		scanf("%s",s+1);
		n=strlen(s+1);
		for(int i=n;i>=1;--i)
		insert(s[i]-'a',i);
		for(int i=2;i<=cnt;++i)
		add(fa[i],i);
		dep[1]=1;
		dfs(1);
		na=read();
		for(int i=1;i<=na;++i)
		{
			int x=read(),y=read();
			int z=lca(book[x],y-x+1);		
			dis[i+cnt]=y-x+1;
			qwq ymh;
			ymh.len=y-x+1;
			ymh.opt=1;
			ymh.id=i+cnt;
			v[z].push_back(ymh);
		}
		nb=read();
		for(int i=1;i<=nb;++i)
		{
			int x=read(),y=read();
			int z=lca(book[x],y-x+1);
			qwq ymh;
			ymh.len=y-x+1;
			ymh.opt=0;
			ymh.id=i+cnt+na;
			v[z].push_back(ymh);
		}
		for(int x=1;x<=cnt;++x)
		{
			int ji=x;
			sort(v[x].begin(),v[x].end());	
			for(int i=v[x].size()-1;i>=0;--i)
			{
				int cur=v[x][i].id;
				add2(ji,cur);
				++du[cur];
				if(!v[x][i].opt)
				ji=cur;
			}
			ed[x]=ji;
		}
		for(int i=2;i<=cnt;++i)
		{
			add2(ed[fa[i]],i);
			du[i]++;
		}		
		m=read();
		for(int i=1;i<=m;++i)
		{
			int x=read(),y=read();
			add2(x+cnt,y+na+cnt);
			du[y+na+cnt]++;
		}
		for(int i=1;i<=na+nb+cnt;++i)
		{
			if(!du[i])
			{
				res[i]=dis[i];
				q.push(i);
			}
		}
		while(!q.empty())
		{
			int x=q.front();
			q.pop();
			for(int i=hed1[x];i;i=b[i].next)
			{
				int y=b[i].to;
				if(res[y]<res[x]+dis[y])
				res[y]=res[x]+dis[y];
				--du[y];
				if(!du[y])
				q.push(y);
			}
		}
		int pd=0;
		ans=0;
		for(int i=1;i<=na+nb+cnt;++i)
		{
			if(du[i])
			{
				pd=1;
				break;
			}
			ans=max(ans,res[i]);
		}
		if(pd==1)
		printf("-1\n");
		else
		printf("%lld\n",ans);
		for(int i=1;i<=na+nb+cnt;++i)
		{
			du[i]=0;
			res[i]=0;
			dis[i]=0;
			ed[i]=0;
			hed1[i]=0;
		}
		for(int i=1;i<=cnt;++i)
		{
			fa[i]=0;
			len[i]=0;
			hed[i]=0;
			v[i].clear();
			for(int j=0;j<=25;++j)
			ch[i][j]=0;
		}
		for(int i=1;i<=n;++i)
		{
			book[i]=0;
			s[i]=0;
		}
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/forever_shi/article/details/89186959
今日推荐