zoukankan      html  css  js  c++  java
  • 题解 P2414 【[NOI2011]阿狸的打字机】

    题目链接

    Solution [NOI2011]阿狸的打字机

    题目大意:给定一颗(Trie)树,多次询问(x)号节点代表的字符串在(y)号节点代表的字符串中出现了多少次

    AC自动机


    分析:首先我们回顾一下(AC)自动机上匹配的过程

    我们沿着文本串在(Trie)图上面走(假设已经用类似路径压缩的办法,把(Trie)树给补全,当然此题直接从根走到(y)即可),走到每个节点,一直沿着(fail)跳,跳到的节点代表能匹配(当前节点代表前缀的后缀)的前缀(有点绕加了个括号)。

    跳到的节点如果是某个字符串的结尾,那么就匹配上了。

    那么这题的暴力算法就是从根走到(y),路径上每个节点跳(fail),走到(x)结尾就把答案加(1)

    显然复杂度无法承受,我们考虑从(x)的角度来考虑

    (fail)边反向就可以得到(fail)树,实际上我们只需要查询(x)为根的子树内,有多少个节点在根到(y)的链

    可以在线做,也可以离线,利用(dfs)序来统计

    我们将询问((x,y))保存在(y)内,进行一次(dfs),在新进入一个节点时在它(dfs)序位置(+1),离开时撤销。对于它所有的询问,直接查询子树和即可

    树状数组可以维护

    #include <cstdio>
    #include <cstring>
    #include <vector>
    #include <queue>
    using namespace std;
    const int maxn = 1e5 + 100;
    struct mpair{int first,second;};
    inline mpair make_pair(int x,int y){return mpair{x,y};}
    extern int ans[maxn];
    namespace bit{
    	int f[maxn];
    	inline int lowbit(int x){return x & (-x);}
    	inline void add(int pos,int x){
    		while(pos < maxn){
    			f[pos] += x;
    			pos += lowbit(pos);
    		}
    	}
    	inline int query(int pos){
    		int res = 0;
    		while(pos){
    			res += f[pos];
    			pos -= lowbit(pos);	
    		}
    		return res;
    	}
    	inline int query(int a,int b){return query(b) - query(a - 1);}
    }
    namespace graph{
    	vector<int> G[maxn];
    	inline void addedge(int from,int to){G[from].push_back(to);}
    	int siz[maxn],dfn[maxn],dfs_tot;
    	inline void dfs(int u){
    		dfn[u] = ++dfs_tot;
    		siz[u] = 1;
    		for(int v : G[u])dfs(v),siz[u] += siz[v];
    	}
    }
    namespace ac{
    	const int siz = 26;
    	int ch[maxn][siz],chhis[maxn][siz],faz[maxn],fail[maxn],tot;
    	vector<mpair> query[maxn]; 
    	inline int idx(char c){return c - 'a';}
    	inline void build(){
    		memcpy(chhis,ch,sizeof(ch)); 
    		queue<int> Q;
    		for(int c = 0;c < siz;c++)
    			if(ch[0][c])Q.push(ch[0][c]);
    		while(!Q.empty()){
    			int u = Q.front();Q.pop();
    			for(int c = 0;c < siz;c++)
    				if(ch[u][c])fail[ch[u][c]] = ch[fail[u]][c],Q.push(ch[u][c]);
    				else ch[u][c] = ch[fail[u]][c];
    		}
    		for(int u = 1;u <= tot;u++)graph::addedge(fail[u],u);
    	}
    	inline void dfs(int u){
    //		printf("%d
    ",u);
    		if(u)bit::add(graph::dfn[u],1);
    		if(u)for(auto p : query[u]){
    //			printf("")
    			ans[p.first] = bit::query(graph::dfn[p.second],graph::dfn[p.second] + graph::siz[p.second] - 1);
    		}
    		for(int c = 0;c < siz;c++)
    			if(chhis[u][c])dfs(chhis[u][c]);
    		if(u)bit::add(graph::dfn[u],-1);
    	}
    }
    char str[maxn];
    int m,now,pos[maxn],ans[maxn],print;
    int main(){
    #ifdef LOCAL
    	freopen("type3.in","r",stdin);
    #endif
    	scanf("%s",str + 1);
    	for(int i = 1;str[i];i++){
    		if(str[i] == 'B')now = ac::faz[now];
    		else if(str[i] == 'P')pos[++print] = now;
    		else{
    			int c = ac::idx(str[i]);
    			if(!ac::ch[now][c])ac::ch[now][c] = ++ac::tot,ac::faz[ac::tot] = now;
    			now = ac::ch[now][c];
    		}
    	}
    	ac::build();
    	graph::dfs(0);
    	scanf("%d",&m);
    	for(int x,y,i = 1;i <= m;i++){
    		scanf("%d %d",&x,&y);
    		ac::query[pos[y]].push_back(make_pair(i,pos[x]));
    	}
    	ac::dfs(0);
    	for(int i = 1;i <= m;i++)printf("%d
    ",ans[i]);
    	return 0;
    }
    
  • 相关阅读:
    loads和dumps的用法
    python实现装饰器
    pycharm 配置 git 方法
    正则表达式——练习一
    fiddler下载安装
    robotframework引入seleniumlibrary报错
    Codeforces-936B Sleepy Game
    Codeforces-940D. Alena And The Heater
    Codeforces-935D. Fafa and Ancient Alphabet
    Java编程规范
  • 原文地址:https://www.cnblogs.com/colazcy/p/13616426.html
Copyright © 2011-2022 走看看