zoukankan      html  css  js  c++  java
  • 喵星球上的点名——记一个用广义SAM根号维护多串的技巧

    喵星球的上的点名

    给定一个字符串集合S,每次给定T询问S中有多少个字符串中包含T,最后询问S中的每一个字符串包含了多少次给定的T。

    思路

    考虑将这S个字符串建立广义SAM,那么我们每次将T放到广义SAM中去匹配,最后匹配到的节点的parent子树中来自不同串的结束位置数就是第一问的答案。

    同样我们每次匹配完之后在节点处打上标记,第二问S中每一个字符串的答案就是每一个结束位置能够一直往上跳链跳到的不同的节点的标记之和。

    考虑如何实现上述过程,在广义SAM中,假设一个节点在SAM中的有效节点数量为(S_i),那么可以证明(sum_{i=1}^{n}S_ileq nsqrt{2n}),于是对于第一问我们只需要对于每一个结束位置暴力标记parent树上的节点,第二问每一个结束位置去暴力统计parent树上的节点即可。

    /*=======================================
     * Author : ylsoi
     * Time : 2019.7.2
     * Problem : luogu2336
     * E-mail : ylsoi@foxmail.com
     * ====================================*/
    #include<bits/stdc++.h>
    
    #define REP(i,a,b) for(int i=a,i##_end_=b;i<=i##_end_;++i)
    #define DREP(i,a,b) for(int i=a,i##_end_=b;i>=i##_end_;--i)
    #define debug(x) cout<<#x<<"="<<x<<" "
    #define fi first
    #define se second
    #define mk make_pair
    #define pb push_back
    typedef long long ll;
    
    using namespace std;
    
    void File(){
    	freopen("luogu2336.in","r",stdin);
    	freopen("luogu2336.out","w",stdout);
    }
    
    template<typename T>void read(T &_){
    	_=0; T f=1; char c=getchar();
    	for(;!isdigit(c);c=getchar())if(c=='-')f=-1;
    	for(;isdigit(c);c=getchar())_=(_<<1)+(_<<3)+(c^'0');
    	_*=f;
    }
    
    string proc(){
    	ifstream f("/proc/self/status");
    	return string(istreambuf_iterator<char>(f),istreambuf_iterator<char>());
    }
    
    const int maxn=2e5+10;
    int n,m,name[maxn],len1[maxn],len2[maxn];
    
    unordered_map<int,int>ch[maxn<<1];
    int fa[maxn<<1],len[maxn<<1],cnt=1,last=1;
    int vis[maxn<<1],sz[maxn<<1],fg[maxn<<1];
    
    void insert(int x){
    	int p=last,np=last=++cnt;
    	len[np]=len[p]+1;
    	while(p && !ch[p][x])ch[p][x]=np,p=fa[p];
    	if(!p)fa[np]=1;
    	else{
    		int q=ch[p][x];
    		if(len[q]==len[p]+1)fa[np]=q;
    		else{
    			int nq=++cnt;
    			ch[nq]=ch[q],len[nq]=len[p]+1,fa[nq]=fa[q];
    			fa[q]=fa[np]=nq;
    			while(p && ch[p][x]==q)ch[p][x]=nq,p=fa[p];
    		}
    	}
    }
    
    void update(int p,int id){
    	for(;p && vis[p]!=id;p=fa[p])
    		vis[p]=id,++sz[p];
    }
    
    int query(int p,int id){
    	int ret=0;
    	for(;p && vis[p]!=id;p=fa[p])
    		vis[p]=id,ret+=fg[p];
    	return ret;
    }
    
    int main(){
    	File();
    
    	read(n),read(m);
    
    	int now=0;
    	REP(i,1,n){
    		read(len1[i]),last=1;
    		REP(j,1,len1[i])read(name[++now]),insert(name[now]);
    		read(len2[i]),last=1;
    		REP(j,1,len2[i])read(name[++now]),insert(name[now]);
    	}
    
    	now=0;
    	REP(i,1,n){
    		int o=1;
    		REP(j,1,len1[i])update(o=ch[o][name[++now]],i);
    		o=1;
    		REP(j,1,len2[i])update(o=ch[o][name[++now]],i);
    	}
    
    	REP(i,1,m){
    		int len0,x,o=1;
    		read(len0);
    		REP(j,1,len0)read(x),o=ch[o][x];
    		printf("%d
    ",sz[o]);
    		++fg[o];
    	}
    
    	memset(vis,0,sizeof(vis));
    
    	now=0;
    	REP(i,1,n){
    		int o=1,ans=0;
    		REP(j,1,len1[i])ans+=query(o=ch[o][name[++now]],i);
    		o=1;
    		REP(j,1,len2[i])ans+=query(o=ch[o][name[++now]],i);
    		printf("%d ",ans);
    	}
    
    	return 0;
    }
    
    
  • 相关阅读:
    SpringMVC从Request域中获取数据
    SpringMVC重定向
    SpringMVC的请求转发的三种方法
    SpringMVC文件上传
    SpringMVC处理请求释放静态资源的三种方式
    jackson实现json转换
    SpringMVC之请求部分
    SpringMVC的执行流程
    Java [Leetcode 39]Combination Sum
    深入解析Java对象的hashCode和hashCode在HashMap的底层数据结构的应用
  • 原文地址:https://www.cnblogs.com/ylsoi/p/11122925.html
Copyright © 2011-2022 走看看