CF547E Mike and Friends 题解

首先,我们可以一眼秒掉AC自动机,一个点的答案就是他以fail为边,子树包含\([l,r]\)的个数的和。然后有人就树套树启动了,我不说是谁。我们发现如果要在线做的话\(O(\log_2^2{n})\)去不掉,最主要的是空间会爆炸,所以我们考虑离线,把询问改为\([1,r]\)的答案减去\([1,l-1]\)的答案,然后暴力加入新的节点,运用线段树/树状数组就可以简单的求出来子树和了。(dfn序列的简单应用),这告诉了我们在时空复杂度搞得时候可以适当的降低要求,比如把在线变成离线,少一些限制则会更容易求解了。

代码:

#include <bits/stdc++.h>
#define int long long
using namespace std;
const int maxn=5e5+10;
int n,m,jie[maxn],now,tot,ch[maxn][26],ans[maxn],sz[maxn],fail[maxn],fa[maxn],x,y,z,C[maxn],cnt,in[maxn],out[maxn];
string s;
vector<pair<int,int> >qq[maxn];
vector<int>tu[maxn];
int insert(string q){
	now=0;
	for(int i=0;i<q.size();i++){
		if(!ch[now][q[i]-'a']){
			tot++;
			fa[tot]=now;
			ch[now][q[i]-'a']=tot;
		}
		now=ch[now][q[i]-'a'];
	}
	return now;
}
void getfail(){
	queue<int>Q;
	for(int i=0;i<26;i++){
		if(ch[0][i]){
			Q.push(ch[0][i]);
		}
	}
	while(!Q.empty()){
		int nn=Q.front();
		Q.pop();
		for(int i=0;i<26;i++){
			if(ch[nn][i]){
				fail[ch[nn][i]]=ch[fail[nn]][i];
				Q.push(ch[nn][i]);
			}
			else{
				ch[nn][i]=ch[fail[nn]][i];
			}
		}
		tu[fail[nn]].push_back(nn);
	}
	return;
}
void dfs(int q){
	cnt++;
	in[q]=cnt;
	for(int i=0;i<tu[q].size();i++){
		dfs(tu[q][i]);
	}
	out[q]=cnt;
	return;
}
int lowbit(int q){
	return q&(-q);
}
void add(int q,int w){
	for(int i=q;i<=cnt;i+=lowbit(i)){
		C[i]++;
	}
	return;
}
int query(int q){
	int he=0;
	for(int i=q;i;i-=lowbit(i)){
		he+=C[i];
	}
	return he;
}
signed main(){
	ios::sync_with_stdio(0);
	cin.tie(0),cout.tie(0);
	cin>>n>>m;
	for(int i=1;i<=n;i++){
		cin>>s;
		jie[i]=insert(s);
	}
	getfail();
	for(int i=1;i<=m;i++){
		cin>>x>>y>>z;
		qq[y].push_back({i,z});
		if(x>1)qq[x-1].push_back({-i,z});
	}
	dfs(0);
	for(int i=1;i<=n;i++){
		now=jie[i];
		while(now){
			add(in[now],1);
			now=fa[now];
		}
		for(int j=0;j<qq[i].size();j++){
			if(qq[i][j].first>0){
				ans[qq[i][j].first]+=query(out[jie[qq[i][j].second]])-query(in[jie[qq[i][j].second]]-1);
			}
			else{
				ans[-qq[i][j].first]-=query(out[jie[qq[i][j].second]])-query(in[jie[qq[i][j].second]]-1);
			}
		}
	}
	for(int i=1;i<=m;i++){
		cout<<ans[i]<<'\n';
	}
	return 0;
}
posted @ 2025-05-10 16:40  特别之处  阅读(16)  评论(0)    收藏  举报