• 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;
    }
    
  • 相关阅读:
    expandafter
    又回到了kde
    朗读软件
    tex bookmarks
    vim命令执行时间
    vim,tex的编译
    utorrent
    火狐的扩展
    linux 无线指示灯闪
    tex溢出报警
  • 原文地址:https://www.cnblogs.com/nofind/p/12087858.html
Copyright © 2020-2023  润新知