• 【题解】2021CCPC华为云挑战赛 重叠的子串


    2021CCPC华为云挑战赛 重叠的子串

    题意

    给定一个只含小写字母的字符串(s)(q)次询问,每次询问给定一个字符串,以(s[l...r])的形式给出,判断(s)中是否存在两个或多个出现的有重叠部分的给定子串。比如在“ababa”​中,两个 “aba” 子串就重叠于中间的字母 “a”,而两个 “ab” 子串就没有发生重叠。(T)组数据。

    (1le nle10^5,1le qle 10^6,1le Tle 20,sum nle 6 imes 10^5,sum qle 3 imes 10^6)

    题解

    (s)(SAM),用set+启发式合并维护(parent)树上每个节点的(endpos)集合,由于合并时只会向set中加入节点,所以容易维护每个节点(u)(endpos)集合中任意两个元素的最小差值,记为(ans[u]),只需在插入时用当前元素和其前后两个元素的差值更新当前节点的答案。对于每个询问,先倍增跳到(parent)树上对应的节点(u)上,再比较串长和(ans[u])即可。

    #include <bits/stdc++.h>
    #define pb(x) emplace_back(x)
    using namespace std;
    using P=pair<int,int>;
    typedef long long ll;
    const int N=200005,M=26;
    char S[N];
    int n,m,x,y;
    vector<int> e[N];
    int anc[N][21],ans[N],id[N];
    set<int> s[N];
    struct sam{
    	int fa[N],len[N],lst,gt,ch[N][M],pos[N];
    	void init(){gt=lst=1;}
    	void init2(){
    		for(int p=1;p<=gt;p++){
    			id[p]=0;ans[p]=n+1;fa[p]=0;
    			e[p].clear();
    			s[p]=move(set<int>{});
    			for(int i=0;i<M;i++)if(ch[p][i])ch[p][i]=0;
    		}
    		lst=gt=1;
    	}
    	void ins(int c,int id){
    		int f=lst,p=++gt;lst=p;
    		len[p]=len[f]+1;pos[p]=id;
    		while(f&&!ch[f][c])ch[f][c]=p,f=fa[f];
    		if(!f){fa[p]=1;return ;}
    		int x=ch[f][c],y=++gt;
    		if(len[x]==len[f]+1){gt--;fa[p]=x;return ;}
    		len[y]=len[f]+1;fa[y]=fa[x];pos[y]=pos[x];fa[x]=fa[p]=y;
    		for(int i=0;i<M;i++)ch[y][i]=ch[x][i];
    		while(f&&ch[f][c]==x)ch[f][c]=y,f=fa[f];
    	}
    	void f1(){
    		for(int u=gt;u>=1;u--){
    			anc[u][0]=fa[u];
    			e[fa[u]].pb(u);
    		}
    		dfs(1);
    		id[0]=1;
    		for(int i=1;i<=n;i++){
    			int c=S[i]-'a';
    			id[i]=ch[id[i-1]][c];
    		}
    	}
    	void dfs(int u){
    		int &tmp=ans[u];tmp=n+1;
    		for(int i=1;i<=20;i++){
    			anc[u][i]=anc[anc[u][i-1]][i-1];
    		}
    		for(auto v:e[u]){
    			dfs(v);
    			tmp=min(tmp,ans[v]);
    			if(u==1){continue;}
    			if(s[u].size()>=s[v].size()){
    				for(auto j:s[v]){
    					auto it=s[u].insert(j).first;
    					if(it!=s[u].begin()){
    						--it;
    						tmp=min(tmp,j-*it);
    						++it;
    					}
    					if((++it)!=s[u].end()){
    						tmp=min(tmp,*it-j);
    					}
    				}
    			}
    			else{
    				for(auto j:s[u]){
    					auto it=s[v].insert(j).first;
    					if(it!=s[v].begin()){
    						--it;
    						tmp=min(tmp,j-*it);
    						++it;
    					}
    					if((++it)!=s[v].end()){
    						tmp=min(tmp,*it-j);
    					}
    				}
    				s[u]=move(s[v]);
    			}
    		}
    	}
    }g;
    void f1(){
    	int Q;
    	scanf("%d%d%s",&n,&Q,S+1);
    	g.init2();
    	for(int i=1;i<=n;i++){
    		g.ins(S[i]-'a',i);
    		s[g.lst].insert(i);
    	}
    	g.f1();
    	for(int i=1;i<=Q;i++){
    		int x,y;scanf("%d%d",&x,&y);
    		int p=id[y],l=y-x+1;
    		for(int i=20;i>=0;i--){
    			int na=anc[p][i];
    			if(na>1&&g.len[na]>=l){
    				p=na;
    			}
    		}
    		if(ans[p]<l){
    			printf("Yes
    ");
    		}
    		else{
    			printf("No
    ");
    		}
    	}
    }
    int main(){
    	int t;scanf("%d",&t);
    	while(t--){
    		f1();
    	}
    	return 0;
    }
    
  • 相关阅读:
    第五次实验作业
    第四次作业
    java三
    java作业二
    java作业一
    作业11
    作业10
    作业9
    作业8
    作业7
  • 原文地址:https://www.cnblogs.com/bobh/p/15172155.html
Copyright © 2020-2023  润新知