建议加强数据
查看原帖
建议加强数据
555833
haozexu楼主2024/9/3 10:41

以下代码: https://www.luogu.com.cn/record/175726038

是在 AC 自动机 fail 树上先求出祖先中的上一个 end 然后暴力跳并标记,理论复杂度是 O(n)\mathcal O(n) 的。总共 O(nq)\mathcal O(nq),可以通过,建议加强数据。

(太菜了不会造数据)

附录:代码

#include<bits/stdc++.h>
using namespace std;
const int N=1e5+5,Q=2e6+5;
//SIZEOF SegT+Trie==312MB
string s[N];int n,q;
namespace ACAM{
	struct Trie{
		int son[26],fail,include,end;
		bool vis;
	}t[Q];
	int tot,rt,endpos[N];
	void Insert(string str,int id){
		int cur=rt;
		for(char c:str){
			if(!t[cur].son[c-'a'])
				t[cur].son[c-'a']=++tot;
			cur=t[cur].son[c-'a'];
		}
		t[cur].end=1,endpos[id]=cur;
	}
	vector<int> e[Q];
	void BuildFail(){
		queue<int> q;
		for(int i=0;i<26;i++){
			if(t[rt].son[i]) q.push(t[rt].son[i]),e[rt].push_back(t[rt].son[i]);
		}
		while(!q.empty()){
			int ln=q.front();q.pop();
			for(int i=0;i<26;i++){
				if(t[ln].son[i])
					t[t[ln].son[i]].fail=t[t[ln].fail].son[i],
					q.push(t[ln].son[i]),//printf("%d FAIL TO %d\n",t[ln].son[i],t[t[ln].son[i]].fail),
					e[t[t[ln].son[i]].fail].push_back(t[ln].son[i]);
				else t[ln].son[i]=t[t[ln].fail].son[i];
			}
		}
	}
	int lstend[Q];
	void dfs(int x,int lste){
		lstend[x]=lste;
		if(t[x].end) lste=x;
//		printf("PING FAILTREE:%d,lste%d\n",x,lste);
		for(int v:e[x]) dfs(v,lste);
	}
	void Modify(string str){
		int cur=rt;vector<int> v;
		for(char c:str){
			cur=t[cur].son[c-'a'];
//			printf("CurPing %d\n",cur);
			int tmp=cur;
			while(!t[tmp].vis and tmp){
//				printf("Upload %d\n",tmp);
				t[tmp].include++,t[tmp].vis=true;
				v.push_back(tmp),tmp=lstend[tmp];
			}
		}
		for(int i:v) t[i].vis=false;
	}
};
#include<ext/pb_ds/assoc_container.hpp>
#include<ext/pb_ds/hash_policy.hpp>
using namespace __gnu_pbds;
typedef unsigned long long ull;
gp_hash_table<ull,int> cnt;
namespace Hash{
	const ull P=13331;
	int mxl;ull target[N];
	ull hash(string s){
		ull hsh=0;
		for(char c:s){
			hsh=hsh*P+ull(c);
//			cerr<<"char "<<c<<" hsh "<<hsh<<"\n";
		}
		return hsh;
	}
//	bool flg;
	void Insert(string s){
		gp_hash_table<ull,bool> vis;
		for(int i=0;i<s.size();i++){
			ull hsh=0;
			for(int j=i;j<=i+mxl-1 and j<s.size();j++){
				hsh=hsh*P+ull(s[j]);
//				if(flg) cerr<<"gog "<<j<<"\n";
				if(vis.find(hsh)!=vis.end())
					continue;
				cnt[hsh]++,vis[hsh]=true;
			}
		}
	}
};
const int B=14;
//const int B=6324;
int main(){
	ios::sync_with_stdio(false);
	cin.tie(0),cout.tie(0);
//	cout<<(sizeof(ACAM::t)+sizeof(SegmentTree::t));
	cin>>n;
	for(int i=1;i<=n;i++){
		cin>>s[i];
	}
	for(int i=1;i<=n;i++){
		if((int)s[i].length()>B){
			ACAM::Insert(s[i],i);
		}else{
			Hash::target[i]=Hash::hash(s[i]);
			Hash::mxl=max(Hash::mxl,(int)s[i].length());
		}
	}
//	cerr<<"MAXL "<<Hash::mxl<<"\n";
	ACAM::BuildFail(),ACAM::dfs(0,0);
	cin>>q;
	while(q--){
		int op,x;
		
		cin>>op;
//		cerr<<"go "<<q<<" op "<<op<<"\n";
		if(op==1){
			string p;cin>>p;
//			cerr<<"LINT A\n";
			ACAM::Modify(p);
//			cerr<<"LINT B\n";
//			cerr<<"SZ "<<p.size()<<"\n";
			Hash::Insert(p);
//			cerr<<"END\n";
		}else{
			cin>>x;
			if(s[x].length()>B){
				cout<<ACAM::t[ACAM::endpos[x]].include<<"\n";
			}else{
				cout<<cnt[Hash::target[x]]<<"\n";
			}
		}
	}
	return 0;
}

注:本来是想根号分治,后来发现把阈值 BB 设为 00 可以通过。

2024/9/3 10:41
加载中...