• CF1207G Indie Album


    CF1207G Indie Album

    首先,如果直接暴力存那 (n) 个文本串空间最大 (n^2) 级别显然不行。

    我一开始以为是“可持久化AC自动机”,想了好久甚至用LCT去维护。那个翻译写“版本”真是害人不浅qwq

    后来发现那就是一颗标准的 (Trie) 树,读入的时候建 (Trie) 即可存下所有的串。

    关于查询,在线不是很好搞,那就离线下来,把询问挂到 (Trie) 上。

    看看现在需要干什么:求出当前 (Trie) 节点所代表的字符串中 (t) 出现了几次。

    这种问题一般都是把询问串建 (ACAM) ,然后跑 (dp) 维护子树和。

    动态就是 CF163E e-Government ,搞个树状数组以及 (fail) 树的 (dfs) 序就能做,因为我们只需要知道子树内出现的状态数,所以是一个单点修改区间求和的问题。

    那么我们把模式串建 (ACAM) ,跑出 (fail) 树的 (dfs) 序。

    在文本串的 (Trie) 上跑 (dfs) ,遍历所有节点回答询问。

    考虑在 (dfs) 的时候记录两个值来表示状态:(u1,u2) 分别表示,在文本串 (Trie) 上的节点编号,在询问串上 (Trie) 图的节点编号。

    (u1) 沿着文本串 (Trie) 跑,(u2) 沿着询问串 (Trie) 图跑,根据 (u1) 回答询问,根据 (u2) 来在 (fail) 树上修改。

    对于每一个 (dfs) 状态, (u2) 所在的节点就是 (u1) 代表的文本串 (Trie) 上前缀的状态,相当于跑单个文本串。

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long LL;
    typedef double db;
    #define x first
    #define y second
    #define sz(v) (int)v.size()
    #define pb(x) push_back(x)
    #define mkp(x,y) make_pair(x,y)
    inline int read(){
    	int x=0,f=1;char c=getchar();
    	while(!isdigit(c)){if(c=='-')f=0;c=getchar();}
    	while(isdigit(c))x=x*10+c-'0',c=getchar();
    	return f?x:-x;
    }
    int rdc(){
    	char ch=getchar();
    	while(!isalpha(ch))ch=getchar();
    	return ch-'a';
    }
    #define N 400005
    int n,m,ch[N][26],ed[N],to[N],ln[N],rn[N],tmr,tr[N],tot,ans[N],fail[N],trie[N][26],cnt;
    vector<int>e[N],q[N];
    void insert(char*str,int id){
    	int u=0;
    	for(int i=0,len=strlen(str);i<len;++i){
    		int c=str[i]-'a';
    		if(!ch[u][c])ch[u][c]=++cnt;
    		u=ch[u][c];
    	}
    	ed[id]=u;
    }
    void build_fail(){
    	queue<int>q;
    	for(int i=0;i<26;++i)if(ch[0][i])q.push(ch[0][i]);
    	while(!q.empty()){
    		int u=q.front();q.pop();
    		for(int i=0;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<=cnt;++i)e[fail[i]].pb(i);
    }
    void dfs1(int u){
    	ln[u]=++tmr;
    	for(int v:e[u])dfs1(v);
    	rn[u]=tmr;
    }
    void add(int x,int d){if(!x)return;for(int i=x;i<=tmr;i+=i&-i)tr[i]+=d;}
    int ask(int x){int res=0;for(int i=x;i>0;i-=i&-i)res+=tr[i];return res;}
    void dfs2(int u1,int u2){
    	add(ln[u2],1);
    	for(int i:q[u1])ans[i]=ask(rn[ed[i]])-ask(ln[ed[i]]-1);
    	for(int i=0;i<26;++i)if(trie[u1][i])dfs2(trie[u1][i],ch[u2][i]);
    	add(ln[u2],-1);
    }
    signed main(){
    	n=read();
    	for(int i=1;i<=n;++i){
    		int op=read(),pre=0,x;
    		if(op==2)pre=read();
    		x=rdc();
    		if(!trie[to[pre]][x])trie[to[pre]][x]=++tot;
    		to[i]=trie[to[pre]][x];
    	}
    	m=read();
    	for(int i=1;i<=m;++i){
    		int x=read();static char str[N];
    		scanf("%s",str);
    		insert(str,i),q[to[x]].pb(i);
    	}
    	build_fail(),dfs1(0),dfs2(0,0);
    	for(int i=1;i<=m;++i)printf("%d
    ",ans[i]);
    	return 0;
    }
    
  • 相关阅读:
    SVNKit学习——基于Repository的操作之print repository tree、file content、repository history(四)
    java操作svn【svnkit】实操
    python笔记38-使用zmail发各种邮件案例代码
    python笔记37-史上最好用的发邮件zmail
    python笔记3-邮件发送(smtplib)
    第9期《python3接口自动化测试》课程,6月29号开学!
    anyproxy学习4-Linux(Centos)搭建anyproxy环境
    anyproxy学习3-修改返回内容(beforeSendResponse)
    anyproxy学习2-rule模块实现接口mock功能
    anyproxy学习1-windows平台安装和抓手机app上https请求
  • 原文地址:https://www.cnblogs.com/zzctommy/p/13889472.html
Copyright © 2020-2023  润新知