• [luogu2414 NOI2011]阿狸的打字机 (AC自动机)


    传送门

    Solution

    我们知道AC自动机上如果有一点A的fail[A]->B那么B为A的一个后缀

    那么我们的问题((x,y))就变为在y中有多少个点直接或间接连向x的终止节点

    如果写暴力的话就是遍历y的所有点,对于每个点,我们往上暴跳fail,如果遇到x单词的结尾就ans+1

    然而我可以利用dfs序和数据结构优美的完成

    首先我们求出fail树(树边与fail相反)的dfs序,并将询问按y排序,然后从头扫读入的字符串,扫的时候给每个点对应的dfs序位置+1。
    每当扫完一个字符串时,求出这个字符串作为y的贡献。
    具体来说就是找到这个字符串对应的x,对每一个x的终止节点,求出子树的权值和即可

    Code

    //By Menteur_Hxy
    #include <queue>
    #include <cmath>
    #include <vector>
    #include <cstdio>
    #include <cstring>
    #include <cstdlib>
    #include <iostream>
    #include <algorithm>
    #define fi first
    #define se second
    #define Re register 
    #define Ms(a,b) memset(a,(b),sizeof(a))
    #define Ee(i,u) for(Re int i=head[u];i;i=nxt[i])
    #define Fo(i,a,b) for(Re int i=(a),_=(b);i<=_;i++)
    #define Ro(i,a,b) for(Re int i=(b),_=(a);i>=_;i--)
    #define Add(a,b) nxt[++cnt]=head[a],to[cnt]=b,head[a]=cnt
    using namespace std;
    typedef pair<int,int> PII;
    
    inline int read() {
    	int x=0,f=1;char c=getchar();
    	while(!isdigit(c)) {if(c=='-')f=-f;c=getchar();}
    	while(isdigit(c)) x=(x<<1)+(x<<3)+c-48,c=getchar();
    	return x*f;
    }
    
    const int L=1e5+10;
    int m,tot,cnt;
    int str[L],nxt[L],to[L],head[L],dfn[L],low[L],ans[L];
    char ch[L];
    vector <PII> As[L];
    
    queue <int> Q;
    struct AC_Automation{
    	int nd[L][26],fail[L],fa[L],ret;
    	AC_Automation() {Ms(nd,0);Ms(fail,0);Ms(fa,0);ret=0;}
    	void ins(char *s) {
    		int len=strlen(s),now=0,*p;
    		Fo(i,0,len-1) {
    			if(s[i]=='P') str[++tot]=now;
    			else {
    				if(s[i]=='B') now=fa[now];
    				else {p=&nd[now][s[i]-'a'];if(!*p)*p=++ret;fa[*p]=now;now=*p;}
    			}
    		} 
    	}
    	void build() {
    		Fo(i,0,25) if(nd[0][i]) fail[nd[0][i]]=0,Q.push(nd[0][i]);
    		while(!Q.empty()) {
    			int now=Q.front(),*p;Q.pop();
    			Fo(i,0,25) if(*(p=&nd[now][i])) fail[*p]=nd[fail[now]][i],Q.push(*p);
    				else *p=nd[fail[now]][i];
    		}
    	}
    }AC;
    
    struct BIT{
    	int da[L];
    	BIT() {clear();}
    	void clear() {Ms(da,0);}
    	void add(int x,int k) {for(;x<=L;x+=x&-x)da[x]+=k;}
    	int qry(int x) {int res=0;for(;x;x-=x&-x)res+=da[x];return res;}
    }T;
    
    void dfs(int u) {
    	dfn[u]=++tot;
    	Ee(i,u) dfs(to[i]);
    	low[u]=tot;
    }
    
    int main() {
    	scanf("%s",ch); AC.ins(ch); AC.build();
    	m=read();
    	Fo(i,1,m) {
    		int x=read(),y=read();
    		As[y].push_back(PII(x,i));
    	}
    	Fo(i,1,AC.ret) Add(AC.fail[i],i); dfs(0);
    	T.add(dfn[0],1); int now=0,tmp=0;
    	for(Re int i=0;ch[i];i++) {
    		if(ch[i]=='P') {
    			tmp++;
    			Fo(j,0,As[tmp].size()-1) {
    				int x=str[As[tmp][j].fi];
    				ans[As[tmp][j].se]=T.qry(low[x])-T.qry(dfn[x]-1);
    			}
    		} else if(ch[i]=='B') T.add(dfn[now],-1),now=AC.fa[now];
    		else now=AC.nd[now][ch[i]-'a'],T.add(dfn[now],1);
    	}
    	Fo(i,1,m) printf("%d
    ",ans[i]);
    	return 0;
    }
    
  • 相关阅读:
    .NET 4.5 Task异步编程学习资料
    ASP.NET MVC5 支持PUT 和DELETE
    Web Api
    jexus linux x64[标准版]
    redis-window 集群配置
    响应式网格视图css
    json字符串到js对象的转换
    Activity中UI框架基本概念
    Spring AOP 详解
    行为触发之Android自动化测试instrumentation(一)
  • 原文地址:https://www.cnblogs.com/Menteur-Hxy/p/9753596.html
Copyright © 2020-2023  润新知