• Codeforces 547E. Mike and Friends 题解


    题目大意:

    • 给定(n)个字符串(s_1,s_2,dots,s_n)
    • (q)次询问(s_k)(s_{l,dots,r})中出现了多少次。

    题目链接:547E. Mike and Friends


    题解:考虑 AC 自动机的 fail 树,将每一个串插入到 AC 自动机中,然后建出 fail 树,一个串出现的次数就是它的 fail 树的子树大小,因为这一道题不是全局查询,所以讲每一个询问差分成(l-1,r)两个询问,排序,每一次对于当前串的链全部加一,然后直接统计即可。

    查询子树和用 dfs 序加上树状数组即可。

    代码:

    #include <queue>
    #include <cstdio>
    using namespace std;
    int abs(int a){
    	return a<0?-a:a;
    }
    const int Maxn=200000;
    const int Maxq=500000;
    int n,q;
    char s[Maxn+5];
    int pos[Maxn+5];
    int dfn[Maxn+5],dfn_tot;
    vector<int> edge[Maxn+5];
    int sz[Maxn+5];
    int k[Maxq+5];
    struct Node{
    	int ch[26];
    	int fail,fa;
    }node[Maxn+5];
    vector<int> que[Maxn+5];
    int id_tot=1;
    int insert(int n){
    	int root=1;
    	for(int i=1;i<=n;i++){
    		if(node[root].ch[s[i]-'a']==0){
    			node[root].ch[s[i]-'a']=++id_tot;
    			node[id_tot].fa=root;
    		}
    		root=node[root].ch[s[i]-'a'];
    	}
    	return root;
    }
    void dfs(int u){
    	dfn[u]=++dfn_tot;
    	sz[u]=1;
    	for(int i=0;i<(int)edge[u].size();i++){
    		int v=edge[u][i];
    		dfs(v);
    		sz[u]+=sz[v];
    	}
    }
    void build(){
    	queue<int> q;
    	for(int i=0;i<26;i++){
    		if(node[1].ch[i]){
    			node[node[1].ch[i]].fail=1;
    			q.push(node[1].ch[i]);
    		}
    		else{
    			node[1].ch[i]=1;
    		}
    	}
    	while(!q.empty()){
    		int u=q.front();
    		q.pop();
    		for(int i=0;i<26;i++){
    			if(node[u].ch[i]){
    				node[node[u].ch[i]].fail=node[node[u].fail].ch[i];
    				q.push(node[u].ch[i]);
    			}
    			else{
    				node[u].ch[i]=node[node[u].fail].ch[i];
    			}
    		}
    	}
    	for(int i=2;i<=id_tot;i++){
    		edge[node[i].fail].push_back(i);
    	}
    	dfs(1);
    }
    int f[Maxn+5];
    void add(int x,int a){
    	for(int i=x;i<=id_tot;i+=(i&(-i))){
    		f[i]+=a;
    	}
    }
    int query(int x){
    	int ans=0;
    	for(int i=x;i>0;i-=(i&(-i))){
    		ans+=f[i];
    	}
    	return ans;
    }
    int ans[Maxq+5];
    int main(){
    	scanf("%d%d",&n,&q);
    	for(int i=1;i<=n;i++){
    		scanf("%s",s+1);
    		int len=0;
    		while(s[++len]!='');
    		len--;
    		pos[i]=insert(len);
    	}
    	build();
    	for(int i=1;i<=q;i++){
    		int l,r;
    		scanf("%d%d%d",&l,&r,&k[i]);
    		if(l>1){
    			que[l-1].push_back(-i);
    		}
    		que[r].push_back(i);
    	}
    	for(int i=1;i<=n;i++){
    		int root=pos[i];
    		while(root!=1){
    			add(dfn[root],1);
    			root=node[root].fa;
    		}
    		for(int j=0;j<(int)que[i].size();j++){
    			int id=abs(que[i][j]);
    			int x=pos[k[id]];
    			if(que[i][j]>0){
    				ans[id]+=query(dfn[x]+sz[x]-1)-query(dfn[x]-1);
    			}
    			else{
    				ans[id]-=query(dfn[x]+sz[x]-1)-query(dfn[x]-1);
    			}
    		}
    	}
    	for(int i=1;i<=q;i++){
    		printf("%d
    ",ans[i]);
    	}
    	return 0;
    }
    
  • 相关阅读:
    C# 一个用到WPF 和 反射的例子.
    Html 效果之 A 标签.
    HttpModule 的权限管理
    C# 入门经典示例.
    CSS 圆角边框
    .NET 平台文件去除行号
    C#调用WinApi关闭电脑屏幕含自动监视有无输入活动检测
    还是XP好啊
    SQL执行效率测试语句
    自用SqlHelper
  • 原文地址:https://www.cnblogs.com/withhope/p/13381072.html
Copyright © 2020-2023  润新知