zoukankan      html  css  js  c++  java
  • 题解「SPOJ8093 JZPGYZ

    转载注明来源:https://www.cnblogs.com/syc233/p/13784426.html


    广义SAM+区间数颜色。

    几篇写广义SAM的题解似乎都没写对啊/fad,都是插入新串时直接将 (las) 设为 (1) 的,在这篇博客中提到这样建出来的广义SAM是有问题的。

    所以这里再写一篇题解来讲一下如何正确使用广义SAM解决这道题(当然也不能保证完全正确,毕竟我也才学广义SAM)。


    对所有模板串建立一个广义SAM,每个结点记录它存储的串的信息的编号。因为在广义SAM中,一个结点可能保存了多个模式串的状态,所以需要每个点开一个vector来记录,而不是单纯的使用一个数组。

    查询时,找到查询串在SAM上的对应结点,那么现在只需要知道这个结点代表的字符串在哪些模板串中出现过。

    由于parent树的性质,若一个结点代表的字符串在某个模板串中出现,那么它的祖先代表的字符串也会在这个模板串中出现。

    于是问题就变成了:查询parent树上一个子树内结点存储的模板串种类数,即子树内颜色数,转换成dfs序即为区间数颜色问题。

    区间数颜色问题可以参考 P1972 [SDOI2009]HH的项链


    ( ext{Code}:)

    #include <iostream>
    #include <cstring>
    #include <cstdio>
    #include <algorithm>
    #include <cmath>
    #include <vector>
    #define Rint register int
    #define INF 0x3f3f3f3f
    using namespace std;
    typedef long long lxl;
    const int maxn=1e4+5,maxq=6e4+5,maxnode=2e5+5;
    
    template <typename T>
    inline void read(T &x)
    {
    	x=0;T f=1;char ch=getchar();
    	while(ch<'0'||ch>'9') {if(ch=='-') f=-1;ch=getchar();}
    	while(ch>='0'&&ch<='9') {x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
    	x*=f;
    }
    
    struct edge
    {
    	int u,v,next;
    	edge(int u,int v,int next):u(u),v(v),next(next){}
    	edge(){}
    }e[maxnode];
    
    int head[maxnode],ecnt;
    
    inline void add(int u,int v)
    {
    	e[ecnt]=edge(u,v,head[u]);
    	head[u]=ecnt++;
    }
    
    int n,m;
    
    struct State
    {
    	int len,fa;
    	int ch[30];
    }S[maxnode];
    
    int tot=1;
    
    inline int insert(int c,int las)
    {
    	int p=las;
    	if(S[p].ch[c])
    	{
    		int q=S[p].ch[c];
    		if(S[q].len==S[p].len+1) return q;
    		else
    		{
    			int nq=++tot;S[nq]=S[q];
    			S[nq].len=S[p].len+1;
    			S[q].fa=nq;
    			for(;p&&S[p].ch[c]==q;p=S[p].fa) S[p].ch[c]=nq;
    			return nq;
    		}
    	}
    	int np=++tot;
    	S[np].len=S[p].len+1;
    	for(;p&&!S[p].ch[c];p=S[p].fa) S[p].ch[c]=np;
    	if(!p) S[np].fa=1;
    	else
    	{
    		int q=S[p].ch[c];
    		if(S[q].len==S[p].len+1) S[np].fa=q;
    		else
    		{
    			int nq=++tot;S[nq]=S[q];
    			S[nq].len=S[p].len+1;
    			S[q].fa=S[np].fa=nq;
    			for(;p&&S[p].ch[c]==q;p=S[p].fa) S[p].ch[c]=nq;
    		}
    	}
    	return np;
    }
    
    struct BIT
    {
    	int sum[maxnode];
    	inline int lowbit(int x){return x&-x;}
    	inline void add(int x,int d)
    	{
    		for(int i=x;i<=tot;i+=lowbit(i))
    			sum[i]+=d;
    	}
    	inline int query(int x)
    	{
    		int res=0;
    		for(int i=x;i>=1;i-=lowbit(i))
    			res+=sum[i];
    		return res;
    	}
    }bit;
    
    struct ques
    {
    	int l,r,id;
    	ques(int l,int r,int id):l(l),r(r),id(id){}
    	ques(){}
    	inline bool operator < (const ques &T)const
    	{
    		return r<T.r;
    	}
    }q[maxq];
    int qcnt;
    
    char s[maxnode<<1];
    int ans[maxq];
    vector<int> color[maxnode];
    int pre[maxn];
    
    int dfn[maxnode],idx[maxnode],siz[maxnode],dfs_cnt;
    
    void dfs(int u)
    {
    	dfn[u]=++dfs_cnt;
    	idx[dfs_cnt]=u;
    	siz[u]=1;
    	for(int i=head[u];~i;i=e[i].next)
    	{
    		int v=e[i].v;
    		dfs(v);
    		siz[u]+=siz[v];
    	}
    }
    
    int main()
    {
    #ifndef ONLINE_JUDGE
    	freopen("SP8093.in","r",stdin);
    #endif
    	read(n),read(m);
    	for(int i=1;i<=n;++i)
    	{
    		scanf(" %s
    ",s+1);
    		int len=strlen(s+1);
    		for(int j=1,las=1;j<=len;++j)
    		{
    			las=insert(s[j]-'a',las);
    			color[las].push_back(i);
    		}
    	}
    	memset(head,-1,sizeof(head));
    	for(int i=2;i<=tot;++i)
    		add(S[i].fa,i);
    	dfs(1);
    	for(int i=1;i<=m;++i)
    	{
    		scanf(" %s
    ",s+1);
    		int u=1,len=strlen(s+1);
    		for(int j=1;j<=len&&u;++j)
    			u=S[u].ch[s[j]-'a'];
    		if(u) q[++qcnt]=ques(dfn[u],dfn[u]+siz[u]-1,i);// 询问离线
    	}
    	sort(q+1,q+qcnt+1);
    	for(int i=1,p=1;i<=qcnt;++i)
    	{
    		int u=idx[p];
    		while(p<=q[i].r)
    		{
    			for(auto c:color[u])
    			{
    				if(pre[c]) bit.add(pre[c],-1);
    				bit.add(pre[c]=p,1);
    			}
    			u=idx[++p];
    		}
    		ans[q[i].id]=bit.query(q[i].r)-bit.query(q[i].l-1);
    	}
    	for(int i=1;i<=m;++i)
    		printf("%d
    ",ans[i]);
    	return 0;
    }
    
    
  • 相关阅读:
    EasyUI Combobox组合框(模糊搜索、默认值绑定)
    Asp.Net下载文件时中途失败问题
    VS使用小技巧之——设置调试时启动项目和启动页
    VS使用小技巧之——给代码添加region
    VS使用小技巧之——引入整个文件夹
    VS使用小技巧之——任务列表
    FineUI给表格行内链接设置弹出窗体
    cnpm私服搭建和发布包
    阿里云产品术语和docker
    angularjs1.x的一些知识点整理
  • 原文地址:https://www.cnblogs.com/syc233/p/13784426.html
Copyright © 2011-2022 走看看