题解 选拔

传送门

首先容易想到一个 \(O(n\sqrt n\log n)\) 的根号分治可以处理 \(|s|>\sqrt n\)\(s\)
但是串长 \(\leqslant \sqrt n\) 的部分就不会做了

那么这其实不是个字符串题

  • 关于树上多模式串匹配的一种 \(O(\frac{n|s|}{\omega})\) 做法:
    发现一个模式串在树上一定是一段向上的加上一段向下的(可以为空)
    那么令 \(f_{i, j, k}\) 为到第 \(i\) 个点,第 \(j\) 个串从下往上匹配了 \([1, k]\) 是否可行
    再令 \(g_{i, j, k}\) 为到第 \(i\) 个点,第 \(j\) 个串从上往下匹配了 \([1, k]\) 是否可行
    如果只有一个模式串可以 bitset 优化转移,预处理字符集大小个转移 bitset,转移时考虑 \(f_{i, k}\to f_{i, k+1}\)
    那么多个模式串的话在模式串之间加分隔符,一样做就可以了
    注意 dfs 实现可能会爆栈,需要拓扑实现
  • bitset 做运算操作时貌似会生成一个同等大小的临时变量
    这一变量在函数结束前貌似不会销毁,且多次操作貌似会生成多个临时变量
    这一特性可能导致递归时爆栈
点击查看代码
#include <bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
#define N 100010
#define ll long long
#define ull unsigned long long
//#define int long long

int n, m;
ull hs[N], rhs[N];
const ull base=13131;
char c[10], buf[N], s[N];
unordered_map<ull, bool> mp;
int head[N], len[N], cnt[N], ecnt, tot;
struct edge{int to, next; char val;}e[N<<1];
inline void add(int s, int t, char w) {e[++ecnt]={t, head[s], w}; head[s]=ecnt;}

namespace force{
	void dfs(int u, int fa, ull h) {
		if (mp.find(h)!=mp.end()) mp[h]=1;
		for (int i=head[u],v; ~i; i=e[i].next) {
			v = e[i].to;
			if (v!=fa) dfs(v, u, h*base+e[i].val);
		}
	}
	void solve() {
		for (int i=1; i<=n; ++i) dfs(i, 0, 0);
		for (int i=1; i<=m; ++i) puts(mp[hs[i]]?"YES":"NO");
	}
}

namespace task1{
	int top, sqr;
	char sta[N];
	ull h[N], pw[N];
	void dfs(int u, int fa) {
		for (int i=head[u]; ~i; i=e[i].next)
			if (e[i].to!=fa) sta[++top]=e[i].val, dfs(e[i].to, u);
	}
	inline ull hashing(int l, int r) {return h[r]-h[l-1]*pw[r-l+1];}
	void calc(int len) {
		for (int i=1; i<=top; ++i) h[i]=h[i-1]*base+sta[i];
		for (int i=len; i<=top; ++i) mp[hashing(i-len+1, i)]=1;
	}
	void solve() {
		sqr=sqrt(n);
		pw[0]=1;
		for (int i=1; i<=n; ++i) pw[i]=pw[i-1]*base;
		dfs(1, 0);
		for (int i=1; i<=sqr; ++i) calc(i);
		for (int i=1; i<=m; ++i) if (len[i]>sqr) calc(len[i]);
		for (int i=1; i<=m; ++i) puts((mp[hs[i]]||mp[rhs[i]])?"YES":"NO");
	}
}

namespace task{
	int sta[N], back[N], top;
	bitset<60005> base, tr[26], f[30010], g[30010], tf, tg, ans;
	void dfs(int u, int fa) {
		sta[++top]=u;
		// f[u]=base; g[u]=base;
		for (int i=head[u],v; ~i; i=e[i].next) {
			v = e[i].to;
			if (v==fa) continue;
			back[v]=u;
			dfs(v, u);
			// tf=(f[v]<<1)&tr[e[i].val-'a'];
			// tg=(g[v]>>1)&tr[e[i].val-'a'];
			// ans|=(tf<<1)&g[u];
			// ans|=(f[u]<<1)&tg;
			// f[u]|=tf;
			// g[u]|=tg;
		}
	}
	void solve() {
		// cout<<"s: "<<s+1<<endl;
		// cout<<double(sizeof(g)*2)/1000/1000<<endl;
		for (int i=1; i<=tot; ++i)
			if (s[i]=='$') base[i]=1;
			else tr[s[i]-'a'][i]=1;
		dfs(1, 0);
		for (int j=top; j; --j) {
			int u=sta[j];
			f[u]=base; g[u]=base;
			for (int i=head[u],v; ~i; i=e[i].next) {
				v = e[i].to;
				if (v==back[u]) continue;
				tf=(f[v]<<1)&tr[e[i].val-'a'];
				tg=(g[v]>>1)&tr[e[i].val-'a'];
				ans|=(tf<<1)&g[u];
				ans|=(f[u]<<1)&tg;
				f[u]|=tf;
				g[u]|=tg;
			}
		}
		for (int l=2,r=3; l<=tot; l=r+1,r=l+1) {
			while (s[r]!='$') ++r;
			// cout<<"s: "; for (int i=l; i<r; ++i) cout<<s[i]; cout<<endl;
			bool any=0;
			for (int i=l; i<=r; ++i) if (ans[i]) any=1;
			puts(any?"YES":"NO");
		}
		// cout<<"---f---"<<endl;
		// for (int i=1; i<=n; ++i) cout<<i<<": "<<f[i]<<endl;
		// cout<<"---g---"<<endl;
		// for (int i=1; i<=n; ++i) cout<<i<<": "<<g[i]<<endl;
		// cout<<"---ans---"<<endl;
		// cout<<ans<<endl;
	}
}

signed main()
{
	freopen("selection.in", "r", stdin);
	freopen("selection.out", "w", stdout);

	scanf("%d", &n);
	memset(head, -1, sizeof(head));
	for (int i=1,u,v; i<n; ++i) {
		scanf("%d%d%s", &u, &v, c);
		add(u, v, *c); add(v, u, *c);
	}
	scanf("%d", &m);
	for (int i=1; i<=m; ++i) {
		scanf("%s", buf+1);
		int t=strlen(buf+1); len[i]=t;
		s[++tot]='$';
		for (int j=1; j<=t; ++j) s[++tot]=buf[j];
		// for (int j=1; j<=t; ++j) hs[i]=hs[i]*base+s[j];
		// for (int j=t; j; --j) rhs[i]=rhs[i]*base+s[j];
		// mp[hs[i]]=0;
	}
	s[++tot]='$';
	// if (n<=4000) force::solve();
	// else task1::solve();
	task::solve();

	return 0;
}
posted @ 2022-03-29 16:15  Administrator-09  阅读(7)  评论(0编辑  收藏  举报