zoukankan      html  css  js  c++  java
  • 题解「CF547E Mike and Friends」

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


    AC自动机+线段树合并。


    将所有字符串插入AC自动机中,建出fail树。

    (s)(t) 的子串,令 (u) 表示 (s) 的末尾字符在AC自动机上对应的结点。由于AC自动机的性质,那么一定存在一个 (t) 在AC自动机中的结点,满足在fail树中它在 (u) 的子树中。

    那么问题就转化为:询问 (s_k) 在AC自动机上的结束结点的子树中,有多少结点属于 (s_{l cdots r}) (即插入Trie时经过的结点)。

    这个问题可以用线段树合并解决。

    每个结点开一个以字符串编号为下标的线段树。插入字符串 (s_{id}) 时,在经过的所有结点的线段树中的 (id) 位置加一,代表这个结点属于 (s_{id})

    将询问离线,线段树合并到一个结点时,在线段树上查询区间和即可。


    代码挺好写的。

    ( ext{Code}:)

    #include <iostream>
    #include <cstring>
    #include <cstdio>
    #include <algorithm>
    #include <cmath>
    #include <vector>
    #include <queue>
    #define Rint register int
    #define INF 0x3f3f3f3f
    using namespace std;
    typedef long long lxl;
    const int maxn=2e5+5,maxq=5e5+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[maxn];
    
    int head[maxn],ecnt;
    
    inline void add(int u,int v)
    {
    	e[ecnt]=edge(u,v,head[u]);
    	head[u]=ecnt++;
    }
    
    struct Segment_Tree
    {
    	int tot;
    	int sum[maxn<<5],ch[maxn<<5][2];
    	inline void update(int p)
    	{
    		sum[p]=sum[ch[p][0]]+sum[ch[p][1]];
    	}
    	void modify(int &p,int l,int r,int ps,int d)
    	{
    		if(!p) p=++tot;
    		sum[p]+=d;
    		if(l==r) return;
    		int mid=(l+r)>>1;
    		if(ps<=mid) modify(ch[p][0],l,mid,ps,d);
    		else modify(ch[p][1],mid+1,r,ps,d);
    	}
    	int query(int p,int l,int r,int L,int R)
    	{
    		if(!sum[p]||(L<=l&&r<=R)) return sum[p];
    		int mid=(l+r)>>1,ans=0;
    		if(L<=mid) ans+=query(ch[p][0],l,mid,L,R);
    		if(R>mid) ans+=query(ch[p][1],mid+1,r,L,R);
    		return ans;
    	}
    	int merge(int x,int y)
    	{
    		if(!x||!y) return x|y;
    		sum[x]+=sum[y];
    		ch[x][0]=merge(ch[x][0],ch[y][0]);
    		ch[x][1]=merge(ch[x][1],ch[y][1]);
    		return x;
    	}
    }st;
    int rt[maxn];
    
    struct querys
    {
    	int l,r,id;
    	querys(int l,int r,int id):l(l),r(r),id(id){}
    	querys(){}
    };
    
    int n,q,idx[maxn];
    vector<querys> vec[maxn];
    int ans[maxq];
    int ch[maxn][30],tot;
    int fail[maxn];
    
    inline void insert(const char *s,int id)
    {
    	int len=strlen(s+1),u=0;
    	for(int i=1;i<=len;++i)
    	{
    		int c=s[i]-'a'+1;
    		if(!ch[u][c]) ch[u][c]=++tot;
    		u=ch[u][c];
    		st.modify(rt[u],1,n,id,1);
    	}
    	idx[id]=u;
    }
    
    inline void GetFail()
    {
    	queue<int> q;
    	memset(fail,-1,sizeof(fail));
    	for(int i=1;i<=26;++i)
    		if(ch[0][i]) q.push(ch[0][i]),fail[ch[0][i]]=0;
    	while(!q.empty())
    	{
    		int u=q.front();q.pop();
    		for(int i=1;i<=26;++i)
    			if(ch[u][i])
    			{
    				fail[ch[u][i]]=ch[fail[u]][i];
    				q.push(ch[u][i]);
    			}
    			else ch[u][i]=ch[fail[u]][i];
    	}
    	for(int i=1;i<=tot;++i)
    		if(~fail[i]) add(fail[i],i);
    }
    
    inline void dfs(int u)
    {
    	for(int i=head[u];~i;i=e[i].next)
    	{
    		int v=e[i].v;
    		dfs(v);
    		rt[u]=st.merge(rt[u],rt[v]);
    	}
    	for(auto v:vec[u])
    		ans[v.id]=st.query(rt[u],1,n,v.l,v.r);
    }
    
    char s[maxn];
    
    int main()
    {
    	// freopen("CF547E.in","r",stdin);
    	read(n),read(q);
    	for(int i=1;i<=n;++i)
    	{
    		scanf(" %s",s+1);
    		insert(s,i);
    	}
    	memset(head,-1,sizeof(head));
    	GetFail();
    	for(int i=1,l,r,k;i<=q;++i)
    	{
    		read(l),read(r),read(k);
    		vec[idx[k]].push_back(querys(l,r,i));
    	}
    	dfs(0);
    	for(int i=1;i<=q;++i)
    		printf("%d
    ",ans[i]);
    	return 0;
    }
    
    
  • 相关阅读:
    poj 3590 The shuffle Problem——DP+置换
    poj 3128 Leonardo's Notebook——思路(置换)
    bzoj 1004 [HNOI2008]Cards && poj 2409 Let it Bead ——置换群
    bzoj 1119 [POI2009]SLO && bzoj 1697 [Usaco2007 Feb]Cow Sorting牛排序——思路(置换)
    bzoj 3944 Sum —— 杜教筛
    bzoj 1367 [ Baltic 2004 ] sequence —— 左偏树
    bzoj 2093 [ Poi 2010 ] Frog —— 滑动窗口 + 倍增
    bzoj 2276 [ Poi 2011 ] Temperature —— 单调队列
    bzoj 2069 [ POI 2004 ] ZAW —— 多起点最短路 + 二进制划分
    NOIP2007普及 守望者的逃离
  • 原文地址:https://www.cnblogs.com/syc233/p/13771152.html
Copyright © 2011-2022 走看看