P6727 [COCI 2015/2016 #5] OOP

题目给出字符串按 * 断开得到前后两段 \(P,S\),即要求满足一下条件的模式串个数:

  1. 具有前缀 \(P\),后缀 \(S\)

  2. \(|P|+|S|\le len\)

然后想到了 销售基因链

正序反序分别建立两棵 trie,则同时具有前缀 \(P\),后缀 \(S\) 需要满足代表该字符串的节点分别在两棵 trie 中的某棵子树内。用 dfs 序刻画,即 \(dfs_1\in [l_1,r_2]\)\(dfs_2\in[l_2,r_2]\)

于是有一个套路的 \(O(q\log^2n)\) 的做法。

将询问离线按 \(|P|+|S|\) 排序后,每次将 \(siz\ge |P|+|S|\) 的模式串插入后即为矩阵查。

优化考虑去除 \(len\) 的限制,建立前缀 trie 的过程中,如果对于 \(s:[1,i]\) 的点,代表具有 \(s:[i+1,n]\) 的后缀,哈希后询问就类似查询子树内某个数的出现次数,扫描线即可。

#include<bits/stdc++.h>
#include <ext/pb_ds/assoc_container.hpp>
//#include<bits/extc++.h>
#include <ext/pb_ds/hash_policy.hpp> 
#define fin(x) freopen(#x".in","r",stdin)
#define fout(x) freopen(#x".out","w",stdout)
#define fr(x) fin(x),fout(x);
#define Fr(x,y) fin(x),fout(y)
#define INPUT(_1,_2,FILE,...) FILE
#define IO(...) INPUT(__VA_ARGS__,Fr,fr)(__VA_ARGS__)
using namespace std;
using namespace __gnu_pbds;
#define mp make_pair
#define pii pair<int,ull>
#define fi first
#define se second
#define pb push_back
#define cfast ios::sync_with_stdio(false);cin.tie(0),cout.tie(0)
#define ll long long
#define ull unsigned long long
#define intz(x,y) memset((x),(y),sizeof((x)))
char *p1,*p2,buf[100000];
#define nc() (p1==p2 && (p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++)
#define tup(x) array<int,(x)>
const int N=1e5+5,M=3e6+5,p=133;
string S[N];vector<ull>hsh[N],w[M];vector<pii>Q[M];
unordered_map<ull,int>f;
int s[M][26],len[N],tot=1,ans[N],sz[M],dfn[M],idx[M],ct;char t[M];ull pw[M];
inline ull H(int id,int l,int r){return hsh[id][r]-hsh[id][l-1]*pw[r-l+1];}
inline void add(int id){
	w[1].pb(H(id,1,len[id]-1));
	for(int i=1,u=1;i<len[id];i++){
		int p=S[id][i]-'a';
		if(!s[u][p])s[u][p]=++tot;
		u=s[u][p],w[u].pb(H(id,i+1,len[id]-1));
	}
}
void dfs(int u){
	idx[dfn[u]=++ct]=u,sz[u]=1;
	for(int i=0;i<26;i++)if(s[u][i])
		dfs(s[u][i]),sz[u]+=sz[s[u][i]];
}
inline void UesugiErii(){
	int n,q;cin>>n>>q;
	for(int i=1;i<=n;i++){
		cin>>S[i],S[i]=' '+S[i],len[i]=S[i].size();
		hsh[i].resize(len[i]+5);
		for(int j=1;j<len[i];j++)
			hsh[i][j]=hsh[i][j-1]*p+S[i][j];
		add(i);
	}
	dfs(1);
	for(int _=1;_<=q;_++){
		cin>>(t+1);ull h=0;int u=1,l=strlen(t+1);
		for(int i=l;i;i--){
			if(t[i]=='*')break;
			h=h+t[i]*pw[l-i];
		}
		for(int i=1;i<=l;i++){
			if(t[i]=='*'){
				Q[dfn[u]-1].pb(mp(-_,h)),
				Q[dfn[u]+sz[u]-1].pb(mp(_,h));
				break;
			}int p=t[i]-'a';
			if(!s[u][p])break;u=s[u][p];
		}
	}
	for(int i=1;i<=ct;i++){
		for(ull x:w[idx[i]])++f[x];
		for(pii x:Q[i])if(f.find(x.se)!=f.end()){
			if(x.fi<0)ans[-x.fi]-=f[x.se];
			else ans[x.fi]+=f[x.se];
		}
	}
	for(int i=1;i<=q;i++)
		cout<<ans[i]<<'\n';
}
signed main(){
	//IO();
	cfast;
	int _=1;//cin>>_;
	for(int i=pw[0]=1;i<=3e6;i++)pw[i]=pw[i-1]*p;
	for(;_;_--)UesugiErii();
	return 0;
}
posted @ 2025-11-21 21:20  Uesugi1  阅读(4)  评论(0)    收藏  举报