ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

Codeforces 666E Forensic Examination 广义后缀自动机+线段树合并

2020-10-31 02:02:55  阅读:288  来源: 互联网

标签:le int Forensic tr Codeforces fa ch Examination define


Codeforces 666E Forensic Examination

题意

给出一个字符串\(s\),\(m\)个字符串\(t_1,t_2,\dots,t_m\),\(q\)次询问,每次询问给出四个整数\(l,r,pl,pr\),问\(t_l,t_{l+1},\dots,t_r\)中哪个字符串中\(s[pl;pr]\)作为子串出现次数最多,输出该\(t_i\)的下标和\(s[pl;pr]\)的出现次数。

\(|s| \le 5\cdot 10^5,m\le 5 \cdot 10^4,\sum|t_i| \le 5 \cdot 10^4,1\le l \le r \le m,1\le pl \le pr \le |s|\)

分析

把所有\(t_i\)后加一个字符'#',然后连起来变成\(t_1\#t_2\#\dots t_n\)建后缀自动机,对自动机上每个状态建线段树,\(cnt[v][i]\)表示状态\(v\)的结束位置属于字符串\(t_i\)的个数,线段树维护区间最大值。

把询问离线,然后用字符串\(s\)直接在自动机上跑,对\(s\)的每个前缀\([1;i]\)在自动机上找到能匹配上的最长后缀所在的状态\(v\),遍历所有询问中\(pr=i\)的,按\(pl\)升序遍历,对于每个询问让\(v\)跳后缀链接,跳到一个\(longest(v)\)刚好大于等于\(i-pl+1\)的状态,然后在这个状态的线段树上区间查询\([l,r]\)的最大值即可。

Code

#include<bits/stdc++.h>
#define rep(i,x,n) for(int i=x;i<=n;i++)
#define per(i,n,x) for(int i=n;i>=x;i--)
#define sz(a) int(a.size())
#define rson mid+1,r,rs[p]
#define pii pair<int,int>
#define lson l,mid,ls[p]
#define ll long long
#define pb push_back
#define mp make_pair
#define se second
#define fi first
using namespace std;
const double eps=1e-8;
const int mod=1e9+7;
const int N=1e6+10;
const int M=2e5+10;
const int inf=1e9;
int n,m,q;
char s[N],t[N];
vector<int>g[N];
struct ppo{
	int l,r,x,id;
	bool operator <(const ppo &o)const{
		return x<o.x;
	}
};
vector<ppo>p[N];
pii ans[N];
pii cmax(pii a,pii b){
	if(a.se==b.se){
		if(a.fi<b.fi) return a;
		return b;
	}
	if(a.se>b.se) return a;
	return b;
}
struct SegmentTree{
    pii tr[M*40];
    int ls[M*40],rs[M*40],tot;
    void up(int x,int l,int r,int &p){
        if(!p) p=++tot;
        if(l==r){
        	tr[p].se++;
        	tr[p].fi=l;
        	return;
        }
        int mid=l+r>>1;
        if(x<=mid) up(x,lson);
        else up(x,rson);
        tr[p]=cmax(tr[ls[p]],tr[rs[p]]);
    }
    int merge(int x,int y,int l,int r){
        if(!x||!y) return x+y;
        int p=++tot,mid=l+r>>1;
        if(l==r){
        	tr[p]=mp(l,tr[x].se+tr[y].se);
        }else{
            ls[p]=merge(ls[x],ls[y],l,mid);
            rs[p]=merge(rs[x],rs[y],mid+1,r);
            tr[p]=cmax(tr[ls[p]],tr[rs[p]]);
        }
        return p;
    }
    pii qy(int dl,int dr,int l,int r,int p){
        if(!p||l>r) return mp(dl,0);
        if(l==dl&&r==dr) return tr[p];
        int mid=l+r>>1;
        if(dr<=mid) return qy(dl,dr,lson);
        else if(dl>mid) return qy(dl,dr,rson);
        else return cmax(qy(dl,mid,lson),qy(mid+1,dr,rson));
    }
}seg;
struct SAM{
    int last,cnt;int ch[M][27],fa[M],len[M],rt[M];
    void insert(int c,int pos){
        int p=last,np=++cnt;last=np;len[np]=len[p]+1;
        for(;p&&!ch[p][c];p=fa[p]) ch[p][c]=np;
        if(!p) fa[np]=1;
        else {
            int q=ch[p][c];
            if(len[q]==len[p]+1) fa[np]=q;
            else  {
                int nq=++cnt;len[nq]=len[p]+1;
                memcpy(ch[nq],ch[q],sizeof ch[q]);
                fa[nq]=fa[q],fa[q]=fa[np]=nq;
                for(;ch[p][c]==q;p=fa[p]) ch[p][c]=nq;
            }
        }
        seg.up(pos,1,m,rt[np]);
    }
    void init(){
        last=cnt=1;
    }
    void dfs(int u){
        for(int x:g[u]){
            dfs(x);
            rt[u]=seg.merge(rt[u],rt[x],1,m);
        }
    }
    void gao(){
        for(int i=2;i<=cnt;i++) g[fa[i]].pb(i);
        dfs(1);
    }
    void solve(){
    	int u=1,l=0;
        for(int i=1;i<=n;i++){
        	while(!ch[u][s[i]-'a']&&u!=1) u=fa[u],l=len[u];
        	if(!ch[u][s[i]-'a']){
        		for(ppo it:p[i]){
        			ans[it.id]=mp(it.l,0);
        		}
        		continue;
        	}
        	u=ch[u][s[i]-'a'];l++;
        	int v=u,dl=l;
        	for(ppo it:p[i]){
        		if(dl<i-it.x+1){
        			ans[it.id]=mp(it.l,0);
        			continue;
        		}
        		while(len[fa[v]]>=i-it.x+1) v=fa[v],dl=len[v];
        		ans[it.id]=seg.qy(it.l,it.r,1,m,rt[v]);
        	}
        }
    }
}sam;
int main(){
    scanf("%s",s+1);
    n=strlen(s+1);
    sam.init();
    scanf("%d",&m);
    for(int i=1;i<=m;i++){
    	scanf("%s",t);
    	int l=strlen(t);
    	for(int j=0;j<l;j++) sam.insert(t[j]-'a',i);
    	if(i!=m) sam.insert(26,i);
    }
    sam.gao();
    scanf("%d",&q);
    for(int i=1,l,r,pl,pr;i<=q;i++){
    	scanf("%d%d%d%d",&l,&r,&pl,&pr);
    	p[pr].pb(ppo{l,r,pl,i});
    }
    for(int i=1;i<=n;i++) sort(p[i].begin(), p[i].end());
    sam.solve();
	for(int i=1;i<=q;i++) printf("%d %d\n",ans[i].fi,ans[i].se);
    return 0;
}

标签:le,int,Forensic,tr,Codeforces,fa,ch,Examination,define
来源: https://www.cnblogs.com/xyq0220/p/13905004.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有