Educational Codeforces Round 71 G. Indie Album

鏈接

點擊跳轉

題解

羣大佬太強了

這題的做法是離線,把查詢串建成ACAC自動機,然後對給定的字典樹進行dfsdfs,同時在自動機上跑,字典樹上每個點都對應跑到ACAC自動機上某個點pp,那麼顯然此時pp以及ppfailfail樹上的所有祖先都匹配到了,最直接的想法是把從pp到根節點上的權值都+1+1,這個看起來像是lctlct或者樹鏈剖分;但其實pp影響到的也只有ppfailfail樹上的祖先,因此我直接給pp的權值+1+1,查詢的時候查詢子樹和就行了

代碼

#include <bits/stdc++.h>
#define eps 1e-8
#define iinf 0x3f3f3f3f
#define linf (1ll<<60)
#define cl(x) memset(x,0,sizeof(x))
#define mod 1073741824ll
#define maxn 400010
#define maxe 400010
using namespace std;
typedef long long ll;
struct Graph
{
	int etot, head[maxn], to[maxe], next[maxe];
	void adde(int a, int b)
	{to[++etot]=b;next[etot]=head[a];head[a]=etot;}
}G;
struct ACautomaton
{
	int trie[maxn][30], tot, fail[maxn];
	void clear(){tot=1;}
	int insert(char *r, int len)
	{
		auto pos=1;
		for(auto i=1;i<=len;i++)
			pos = trie[pos][r[i]] ? trie[pos][r[i]] : trie[pos][r[i]]=++tot;
		return pos;
	}
	int append(int pos, int x)
	{
		if(trie[pos][x])return trie[pos][x];
		else return trie[pos][x]=++tot;
	}
	void build()
	{
		queue<int> q;
		int u, v, f;
		q.push(1);
		while(!q.empty())
		{
			u=q.front(); q.pop();
			for(auto i=1;i<=26;i++)
				if(trie[u][i])
				{
					v=trie[u][i];
					for(f=fail[u];f and !trie[f][i];f=fail[f]);
					fail[v] = f ? trie[f][i] : 1;
					q.push(v);
				}
		}
	}
	int move(int pos, int c)
	{
		for(;pos and !trie[pos][c];pos=fail[pos]);
		return pos ? trie[pos][c] : 1;
	}
}trie, aca;
struct BIT
{
	int bit[maxn], n;
	void init(int N){n=N;}
	int lowbit(int x){return x&-x;}
	void add(int pos, int v){for(;pos<=n;pos+=lowbit(pos))bit[pos]+=v;}
	int sum(int pos)
	{
		int ans=0;
		for(;pos;pos-=lowbit(pos))ans+=bit[pos];
		return ans;
	}
}bit;
int tid[maxn], ltid[maxn], rtid[maxn], tim;
void dfs(int pos)
{
	tid[pos]=ltid[pos]=++tim;
	for(auto p=G.head[pos];p;p=G.next[p])
		dfs(G.to[p]);
	rtid[pos]=tim;
}
int ans[maxn], aca_endp[maxn], trie_endp[maxn];
vector<int> q[maxn];
void solve(int pos, int aca_pos)
{
	bit.add(tid[aca_pos],+1);
	for(auto x:q[pos])
		ans[x] = bit.sum(rtid[aca_endp[x]]) - bit.sum(ltid[aca_endp[x]]-1);
	for(int i=1;i<=26;i++)
		if(trie.trie[pos][i])
			solve(trie.trie[pos][i],aca.move(aca_pos,i));
	bit.add(tid[aca_pos],-1);
}
char s[maxn];
int main()
{
	ios::sync_with_stdio(false);
	int i, j, n, m, type;
	char c;
	trie.clear();
	aca.clear();
	cin>>n;
	for(i=1;i<=n;i++)
	{
		cin>>type;
		if(type==1)
		{
			cin>>c;
			trie_endp[i]=trie.append(1,int(c-'a'+1));
		}
		else
		{
			cin>>j>>c;
			trie_endp[i]=trie.append(trie_endp[j],int(c-'a'+1));
		}
	}
 
	cin>>m;
	for(i=1;i<=m;i++)
	{
		cin>>j>>s+1;
		int len=strlen(s+1);
		for(int j=1;j<=len;j++)s[j]=s[j]-'a'+1;
		aca_endp[i] = aca.insert(s,len);
		q[trie_endp[j]].push_back(i);
	}
 
	aca.build();
	for(i=2;i<=aca.tot;i++)G.adde(aca.fail[i],i);
	dfs(1);
 
	bit.init(tim);
	solve(1,1);
	for(i=1;i<=m;i++)cout<<ans[i]<<'\n';
	return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章