CF666E Forensic Examination

题意


今天发生了一个叫nofind的蒟蒻因为while写成if调了一下午的故事。


首先考虑这两个限制:

1.(S[sl...sr])这个子串。
2.在(T[ql..qr])这些字符串中。

我们先对所有的(T_i)建出一个广义后缀自动机,不会广义后缀自动机的出门左转这道题

先考虑第二个限制:

之后我们对(SAM)上的每个点用一个动态开点线段树维护答案,线段树以([1,m])为下标,叶子结点([l,l])放的是该节点在(T_l)中出现的次数,之后我们向上合并并且维护最大值的位置,这个可以用经典的后缀自动机+线段树合并的套路做。

在实现时我用了(STL)(pair),第一关键字是出现次数,第二关键字是位置,同时第二关键字取了负数,这样可以直接两个(pair)(max)

再考虑第一个限制:

我们只要找到子串(S[sl...sr])所在的节点,之后线段树上直接查询即可。那么接下来就要找到(S[sl...sr])所在节点。

我们可以先找到(S[1...sr]),之后倍增跳到最后一个一个点(x)(x)满足(len_xgeqslant (sr-sl+1)),那么(x)即为所求。

但是显然我们不能每次询问都暴力找,于是我们将询问离线,对(S)的每个位置开一个(vector),将询问((sl,sr))放在(sr)(vector)中。之后在(SAM)上对(S)进行匹配,到了第(i)个位置时,所有以(i)为结尾的子串必定是当前节点的祖先,我们这时倍增处理所有以(i)为结尾的询问即可。

code:

#include<bits/stdc++.h>
using namespace std;
#define pii pair<int,int>
#define mkp make_pair
#define fir first
#define sec second
const int maxn=1e6+10;
const int maxQ=5*1e5+10;
int n,m,Q,cnt_edge,tot,lg;
int head[maxn],root[maxn];
int f[maxn][18];
char s[maxn],t[maxn];
pii ans[maxQ];
vector<int>qr_id[maxn];
struct edge{int to,nxt;}e[maxn];
inline void add_edge(int u,int v)
{
	e[++cnt_edge].nxt=head[u];
	head[u]=cnt_edge;
	e[cnt_edge].to=v;
}
struct Query{int l1,r1,l2,r2,id;}qr[maxQ];
struct Seg
{
	#define lc(p) seg[p].lc
	#define rc(p) seg[p].rc
	#define data(p) seg[p].data	
	int lc,rc;
	pii data;
}seg[maxn*35];
inline void up(int p){data(p)=max(data(lc(p)),data(rc(p)));}
void add(int& p,int l,int r,int pos)
{
	if(!p)p=++tot;
	if(l==r){data(p).fir++,data(p).sec=-l;return;}
	int mid=(l+r)>>1;
	if(pos<=mid)add(lc(p),l,mid,pos);
	else add(rc(p),mid+1,r,pos);
	up(p);
}
int merge(int p,int q,int l,int r)
{
	if(!p||!q)
	{
		int x=++tot;
		seg[x]=seg[p+q];
		return x;
	}
	int mid=(l+r)>>1,x=++tot;
	if(l==r){data(x).fir=data(p).fir+data(q).fir;data(x).sec=-l;return x;}
	lc(x)=merge(lc(p),lc(q),l,mid);
	rc(x)=merge(rc(p),rc(q),mid+1,r);
	up(x);
	return x;
}
pii query(int p,int l,int r,int ql,int qr)
{
	if(!p)return mkp(0,-ql);
	if(l>=ql&&r<=qr)return data(p);
	int mid=(l+r)>>1;pii res=mkp(0,-ql);
	if(ql<=mid)res=max(res,query(lc(p),l,mid,ql,qr));
	if(qr>mid)res=max(res,query(rc(p),mid+1,r,ql,qr));
	return res;
}
struct SAM
{
	int last,tot;
	int fa[maxn],len[maxn];
	int ch[maxn][26];
	SAM(){last=tot=1;}
	inline void add(int c)
	{
		if(ch[last][c]&&len[ch[last][c]]==len[last]+1){last=ch[last][c];return;}
		int now=++tot;len[now]=len[last]+1;
		int p=last;
		while(p&&!ch[p][c])ch[p][c]=now,p=fa[p];
		if(!p){fa[now]=1;last=now;return;}
		int q=ch[p][c];
		bool flag=0;
		if(len[q]==len[p]+1)fa[now]=q;
		else
		{
			if(p==last)flag=1;
			int nowq=++tot;len[nowq]=len[p]+1;
			memcpy(ch[nowq],ch[q],sizeof(ch[q]));
			while(p&&ch[p][c]==q)ch[p][c]=nowq,p=fa[p];
			fa[nowq]=fa[q],fa[q]=fa[now]=nowq;
			if(flag)last=nowq;
		}
		if(!flag)last=now;
	}
}sam;
void dfs(int x)
{
	for(int i=1;i<=lg;i++)f[x][i]=f[f[x][i-1]][i-1];
	for(int i=head[x];i;i=e[i].nxt)
	{
		int y=e[i].to;
		f[y][0]=x;dfs(y);
		root[x]=merge(root[x],root[y],1,m);
	}
}
inline int find(int x,int len)
{
	for(int i=lg;~i;i--)if(f[x][i]&&sam.len[f[x][i]]>=len)x=f[x][i];
	return x;
}
inline void solve()
{
	int now=1,nowl=0;
	for(int i=1;i<=n;i++)
	{
		int c=s[i]-'a';
		while(now&&!sam.ch[now][c])now=sam.fa[now],nowl=sam.len[now];
		if(!now){now=1;nowl=0;continue;}
		now=sam.ch[now][c];nowl++;
		for(unsigned int j=0;j<qr_id[i].size();j++)
		{
			int id=qr_id[i][j];
			if(qr[id].r1-qr[id].l1+1>nowl)continue;
			int tmp=find(now,i-qr[id].l1+1);
			ans[id]=query(root[tmp],1,m,qr[id].l2,qr[id].r2);
		}
	}
}
int main()
{
	//freopen("test.in","r",stdin);
	//freopen("test.out","w",stdout);
	scanf("%s",s+1);n=strlen(s+1);
	scanf("%d",&m);
	for(int i=1;i<=m;i++)
	{
		sam.last=1;
		scanf("%s",t+1);
		int len=strlen(t+1);
		for(int j=1;j<=len;j++)sam.add(t[j]-'a'),add(root[sam.last],1,m,i);
	}
	scanf("%d",&Q);
	for(int i=1;i<=Q;i++)scanf("%d%d%d%d",&qr[i].l2,&qr[i].r2,&qr[i].l1,&qr[i].r1);
	for(int i=1;i<=Q;i++)qr_id[qr[i].r1].push_back(i);
	for(int i=2;i<=sam.tot;i++)add_edge(sam.fa[i],i);
	lg=(int)log2(sam.tot)+1;dfs(1);
	solve();
	for(int i=1;i<=Q;i++)if(!ans[i].fir)ans[i].sec=-qr[i].l2;
	for(int i=1;i<=Q;i++)printf("%d %d
",-ans[i].sec,ans[i].fir);
	return 0;
}
原文地址:https://www.cnblogs.com/nofind/p/12087858.html