zoukankan      html  css  js  c++  java
  • 【题解】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;
    }
    
  • 相关阅读:
    多种方式安装GitLabRunner
    rpm,docker,k8s三种方式安装部署GitLab服务
    利用curl命令访问Kubernetes API server
    在客户端电脑使用 kubectl 远程管理 Kubernetes
    利用 Nginx 反向代理搭建本地 yum 服务器
    Jenkins和Gitlab CI/CD自动更新k8s中pod使用的镜像说明
    1.在 Kubernetes 在快速安装 Harbor
    4.Gitlab CI 与 Kubernetes 的结合
    3.在 Kubernetes 上安装 Gitlab CI Runner
    2. 在 Kubernetes 上安装 Gitlab
  • 原文地址:https://www.cnblogs.com/bobh/p/15172155.html
Copyright © 2011-2022 走看看