正睿 25 年省选联考 Day 19

正睿 25 年省选联考 Day 19

\(\text{Link}\)

得分

T1 T2 T3 总分 排名
\(10\) \(90\) \(70\) \(170\) \(6/18\)

题解

T1 陈太阳的石子游戏

由于黑堆每次的操作顺序是固定的,所以我们可以将所有黑堆看成一个整体。剩下的白堆显然就是一个 Nim 游戏,每一个白堆的 SG 函数值是 \(\text{SG}(x)=x\)。现在我们要求的就是黑堆的 SG 函数。

打表可以发现,如果我们令 \(m\) 表示黑堆中最小堆的石头数,\(cnt\) 表示有最小堆出现了几次,那么我们可以得出黑堆的 SG 函数为 \(m-(cnt+[所有黑堆大小相同])\bmod 2\)。我们的目标是后手必胜,那么就要求所有 SG 函数异或和为 \(0\)

考虑枚举 \(m,cnt\),此时比 \(m\) 小的堆一定都是白色,我们只用看比当前堆大的数即可。我们要求和某个数异或和为 \(0\) 的选数方案,显然用线性基实现一下即可。复杂度 \(O(n\log n)\)。注意特判当所有黑堆大小不同的时候除了 \(m\) 以外必须要再选一个数。

#include <bits/stdc++.h>
#define il inline
#define int long long

using namespace std;

const int Maxn = 2e5 + 5;
const int Inf = 2e9;
const int Mod = 1e9 + 7;
il int Add(int x, int y) {return x + y >= Mod ? x + y - Mod: x + y;} il void pls(int &x, int y) {x = Add(x, y);}
il int Del(int x, int y) {return x - y < 0 ? x - y + Mod : x - y;} il void sub(int &x, int y) {x = Del(x, y);}
il int qpow(int a, int b, int P = Mod) {int res = 1; for(; b; a = 1ll * a * a % P, b >>= 1) if(b & 1) res = 1ll * res * a % P; return res;}
il int Inv(int a) {return qpow(a, Mod - 2);}
template <typename T> il void chkmax(T &x, T y) {x = (x >= y ? x : y);}
template <typename T> il void chkmin(T &x, T y) {x = (x <= y ? x : y);}
template <typename T>
il void read(T &x) {
	x = 0; char ch = getchar(); bool flg = 0;
	for(; ch < '0' || ch > '9'; ch = getchar()) flg = (ch == '-');
	for(; ch >= '0' && ch <= '9'; ch = getchar()) x = (x << 1) + (x << 3) + (ch ^ 48);
	flg ? x = -x : 0;
}
template <typename T>
il void write(T x, bool typ = 1) {
	static short Stk[50], Top = 0;
	x < 0 ? putchar('-'), x = -x : 0;
	do Stk[++Top] = x % 10, x /= 10; while(x);
	while(Top) putchar(Stk[Top--] | 48);
	typ ? putchar('\n') : putchar(' ');
}
il void IOS() {ios::sync_with_stdio(0); cin.tie(0), cout.tie(0);}
il void File() {freopen("in.txt", "r", stdin); freopen("out.txt", "w", stdout);}
bool Beg;

int n, a[Maxn];
int pre[Maxn], suf[Maxn];
namespace LB {
	int p[62];
	int cnt;
	void insert(int x) {
		for(int i = 61; i >= 0; i--) {
			if(!(x >> i)) continue;
			if(!p[i]) {p[i] = x; return ;}
			x ^= p[i];
		}
		cnt++;
	}
	int query(int x) {
		for(int i = 61; i >= 0; i--) {
			if(!(x >> i)) continue;
			if(!p[i]) return 0;
			x ^= p[i];
		}
		return qpow(2, cnt);
	}
}

int fac[Maxn], inv[Maxn];
void init() {
	fac[0] = 1; for(int i = 1; i <= n; i++) fac[i] = 1ll * fac[i - 1] * i % Mod;
	inv[n] = Inv(fac[n]); for(int i = n; i >= 1; i--) inv[i - 1] = 1ll * inv[i] * i % Mod;
}

int C(int n, int m) {
	if(n < 0 || m < 0 || n < m) return 0;
	return 1ll * fac[n] * inv[m] % Mod * inv[n - m] % Mod;
}

bool End;
il void Usd() {cerr << (&Beg - &End) / 1024.0 / 1024.0 << "MB " << (double)clock() * 1000.0 / CLOCKS_PER_SEC << "ms\n"; }
signed main() {
	read(n);
	init();
	for(int i = 1; i <= n; i++) read(a[i]);
	sort(a + 1, a + n + 1);
	for(int i = 1; i <= n; i++) pre[i] = pre[i - 1] ^ a[i];
	for(int i = n; i >= 1; i--) suf[i] = suf[i + 1] ^ a[i];
	int ans = 0;
	if(pre[n] == 0) ans++;
	for(int i = n; i >= 1;) {
		int pos = i, num = 0;
		while(a[pos] == a[i]) pos--, num++;
		for(int j = 1; j <= num; j++) {
			int ret1 = a[i] - ((j + 1) & 1), ret2 = a[i] - (j & 1);
			if((num - j) & 1) ret1 ^= a[i], ret2 ^= a[i];
			if((pre[pos] ^ ret1 ^ suf[i + 1]) == 0) pls(ans, C(num, j));
			pls(ans, 1ll * C(num, j) * LB::query(pre[pos] ^ ret2) % Mod);
			if((pre[pos] ^ ret2 ^ suf[i + 1]) == 0) sub(ans, C(num, j));
		}
		for(int j = 1; j <= num; j++) LB::insert(a[i]);
		i = pos;
	}
	write(ans);
    Usd();
	return 0;
}

附上打表代码:

#include <bits/stdc++.h>
#define il inline

using namespace std;

const int Maxn = 2e5 + 5;
const int Inf = 2e9;
const int Mod = 1e9 + 7;
il int Add(int x, int y) {return x + y >= Mod ? x + y - Mod: x + y;} il void pls(int &x, int y) {x = Add(x, y);}
il int Del(int x, int y) {return x - y < 0 ? x - y + Mod : x - y;} il void sub(int &x, int y) {x = Del(x, y);}
il int qpow(int a, int b, int P = Mod) {int res = 1; for(; b; a = 1ll * a * a % P, b >>= 1) if(b & 1) res = 1ll * res * a % P; return res;}
il int Inv(int a) {return qpow(a, Mod - 2);}
template <typename T> il void chkmax(T &x, T y) {x = (x >= y ? x : y);}
template <typename T> il void chkmin(T &x, T y) {x = (x <= y ? x : y);}
template <typename T>
il void read(T &x) {
	x = 0; char ch = getchar(); bool flg = 0;
	for(; ch < '0' || ch > '9'; ch = getchar()) flg = (ch == '-');
	for(; ch >= '0' && ch <= '9'; ch = getchar()) x = (x << 1) + (x << 3) + (ch ^ 48);
	flg ? x = -x : 0;
}
template <typename T>
il void write(T x, bool typ = 1) {
	static short Stk[50], Top = 0;
	x < 0 ? putchar('-'), x = -x : 0;
	do Stk[++Top] = x % 10, x /= 10; while(x);
	while(Top) putchar(Stk[Top--] | 48);
	typ ? putchar('\n') : putchar(' ');
}
il void IOS() {ios::sync_with_stdio(0); cin.tie(0), cout.tie(0);}
il void File() {freopen("in.txt", "r", stdin); freopen("out.txt", "w", stdout);}
bool Beg;

int n, m, a[Maxn];

bool check() {
	for(int i = 1; i <= n; i++) if(a[i]) return 0;
	return 1;
}

int hsh() {
	int res = 0;
	for(int i = 1; i <= n; i++) res = res * 10 + a[i];
	return res;
}
map <int, int> mp;

int dfs(int x) {
	int hs = hsh();
	if(mp.find(hs) != mp.end()) return mp[hs];
	if(check()) {
		for(int i = 1; i <= n; i++) cout << a[i] << " "; cout << ": 0\n";
		return mp[hs] = 0;
	}
	bool vis[55];
	for(int i = 0; i <= 54; i++) vis[i] = 0;
	for(int i = 1; i <= n; i++) {
		if(!a[i]) continue;
		for(int j = 1; j <= a[i]; j++) {
			a[i] -= j;
			vis[dfs(x + 1)] = 1;
			a[i] += j;
		}
		break;
	}
	int mex = 0;
	while(vis[mex]) mex++;
	for(int i = 1; i <= n; i++) cout << a[i] << " "; cout << ": " << mex << '\n';
	return mp[hs] = mex;
	
}

void dfs(int x, int w) {
	if(x == n + 1) {
		int tmp = dfs(0);
		return ;
	}
	for(int i = w; i <= m; i++) {
		a[x] = i; dfs(x + 1, i);
	}
}

bool End;
il void Usd() {cerr << (&Beg - &End) / 1024.0 / 1024.0 << "MB " << (double)clock() * 1000.0 / CLOCKS_PER_SEC << "ms\n"; }
int main() {
	read(n); read(m);
	dfs(0, 0);
    Usd();
	return 0;
}

T2 陈阳太的集合

考虑倒过来完成这个过程,相当于我们要求每次将一个集合拆成两个集合,然后求不同方案数。令 \(f_n\) 表示将 \(n\) 个元素拆分的方案数,则转移如下:

  • \(n\) 个点单独成为一个集合,方案为 \(1\)
  • 枚举给第一个集合多少个数,乘上组合数就是转移。不过由于左右集合不互相区分,所以还要乘 \(\dfrac{1}{2}\)

那么转移方程就是:

\[f_n=1+\dfrac{1}{2}\sum_{i=1}^{n-1} \binom{n}{i} f_if_{n-i} \]

这个转移很像卷积形式,考虑指数生成函数 \(F(x)=\sum f_i \dfrac{x^i}{i!}\),那么展开一下有:

\[\begin{aligned} &f_n=1+\dfrac{1}{2}\sum_{i=1}^{n-1} \binom{n}{i} f_if_{n-i}\\ \Rightarrow&f_n=1+\dfrac{1}{2}\sum_{i=0}^{n} \binom{n}{i} f_if_{n-i}-f_n+\dfrac{1}{2}[n=0]\\ \Rightarrow&2f_n=1+\dfrac{1}{2}\sum_{i=0}^{n} \binom{n}{i} f_if_{n-i}+\dfrac{1}{2}[n=0]\\ \Rightarrow&2\frac{f_n}{n!}=\dfrac{1+\frac{1}{2}[n=0]}{n!}+\dfrac{1}{2}\sum_{i=0}^{n} \frac{f_i}{i!}\frac{f_{n-i}}{(n-i)!}\\ \end{aligned} \]

写成生成函数就是 \(F(x)=e^x+\dfrac{1}{2}+\dfrac{1}{2}F^2(x)\)。解一下这个二次方程就是 \(F(x)=2-\sqrt{3-2e^x}\)(可以通过 \(f_0=1\) 判断取正还是负)。所以用多项式开根处理一下即可,复杂度 \(O(n\log n)\)

#include <bits/stdc++.h>
#define il inline

using namespace std;

const int Maxn = (1 << 21) + 1;
const int Inf = 2e9;
const int Mod = 998244353;
const int YG = 3, InvG = 332748118, Inv2 = 499122177;
il int Add(int x, int y) {return x + y >= Mod ? x + y - Mod: x + y;} il void pls(int &x, int y) {x = Add(x, y);}
il int Del(int x, int y) {return x - y < 0 ? x - y + Mod : x - y;} il void sub(int &x, int y) {x = Del(x, y);}
il int qpow(int a, int b, int P = Mod) {int res = 1; for(; b; a = 1ll * a * a % P, b >>= 1) if(b & 1) res = 1ll * res * a % P; return res;}
il int Inv(int a) {return qpow(a, Mod - 2);}
template <typename T> il void chkmax(T &x, T y) {x = (x >= y ? x : y);}
template <typename T> il void chkmin(T &x, T y) {x = (x <= y ? x : y);}
template <typename T>
il void read(T &x) {
	x = 0; char ch = getchar(); bool flg = 0;
	for(; ch < '0' || ch > '9'; ch = getchar()) flg = (ch == '-');
	for(; ch >= '0' && ch <= '9'; ch = getchar()) x = (x << 1) + (x << 3) + (ch ^ 48);
	flg ? x = -x : 0;
}
template <typename T>
il void write(T x, bool typ = 1) {
	static short Stk[50], Top = 0;
	x < 0 ? putchar('-'), x = -x : 0;
	do Stk[++Top] = x % 10, x /= 10; while(x);
	while(Top) putchar(Stk[Top--] | 48);
	typ ? putchar('\n') : putchar(' ');
}
il void IOS() {ios::sync_with_stdio(0); cin.tie(0), cout.tie(0);}
il void File() {freopen("in.txt", "r", stdin); freopen("out.txt", "w", stdout);}
bool Beg;

int F[Maxn], G[Maxn]; 
int lim = 1;
int r[Maxn];
il void NTT(int *a, int n, int typ) {
	for(int i = 0; i < n; i++) if(i < r[i]) swap(a[i], a[r[i]]);
	for(int h = 1; h < n; h <<= 1) {
		int cur = qpow(typ == 1 ? YG : InvG, (Mod - 1) / (h << 1));
		for(int i = 0; i < n; i += (h << 1)) {
			int w = 1;
			for(int j = 0; j < h; j++, w = 1ll * w * cur % Mod) {
				int x = a[i + j], y = 1ll * a[i + j + h] * w % Mod;
				a[i + j] = Add(x, y);
				a[i + j + h] = Del(x, y);
			}
		}
	}
	if(typ == -1) {
		int iv = Inv(n);
		for(int i = 0; i < n; i++) a[i] = 1ll * a[i] * iv % Mod;
	}
}

int A[Maxn], B[Maxn];
il void Inv(int *a, int *b, int n) {
	b[0] = Inv(a[0]);
	for(int lim = 2; lim < (n << 1); lim <<= 1) {
		int len = lim << 1;
		for(int i = 0; i < lim; i++) A[i] = a[i], B[i] = b[i];
		for(int i = 0; i < len; i++) r[i] = (r[i >> 1] >> 1) | ((i & 1) * (len >> 1));
		NTT(A, len, 1), NTT(B, len, 1);
		for(int i = 0; i < len; i++)  b[i] = 1ll * B[i] * Del(2, 1ll * A[i] * B[i] % Mod) % Mod;
		NTT(b, len, -1);
		for(int i = lim; i < len; i++) b[i] = 0;
	}
	for(int i = 0; i <= (n << 1); i++) A[i] = B[i] = 0;
}

int C[Maxn], D[Maxn];
il void Sqrt(int *a, int *b, int n) {
	b[0] = 1;
	for(int lim = 2; lim < (n << 1); lim <<= 1) {
		int len = lim << 1;
		for(int i = 0; i < lim; i++) C[i] = a[i];
		Inv(b, D, lim);
		for(int i = 0; i < len; i++) r[i] = (r[i >> 1] >> 1) | ((i & 1) * (len >> 1));
		NTT(C, len, 1), NTT(D, len, 1);
		for(int i = 0; i < len; i++) C[i] = 1ll * C[i] * D[i] % Mod;
		NTT(C, len, -1);
		for(int i = 0; i < lim; i++) b[i] = 1ll * Add(b[i], C[i]) * Inv2 % Mod;
	}
	for(int i = 0; i <= (n << 1); i++) C[i] = D[i] = 0;
}

int T, n;

int fac[Maxn], inv[Maxn];
void init(int N) {
	fac[0] = 1; for(int i = 1; i <= N; i++) fac[i] = 1ll * fac[i - 1] * i % Mod;
	inv[N] = Inv(fac[N]); for(int i = N; i >= 1; i--) inv[i - 1] = 1ll * inv[i] * i % Mod;
	for(int i = 0; i <= N; i++) F[i] = Mod - 2ll * inv[i] % Mod;
	F[0] = 1; Sqrt(F, G, 1 << 20);
	for(int i = 0; i <= N; i++) G[i] = Mod - G[i];
	pls(G[0], 2);
}

bool End;
il void Usd() {cerr << (&Beg - &End) / 1024.0 / 1024.0 << "MB " << (double)clock() * 1000.0 / CLOCKS_PER_SEC << "ms\n"; }
int main() {
	read(T); init(1e6);
	while(T--) {
		read(n); write(Del(1ll * G[n] * fac[n] % Mod, 1));
	}
    Usd();
	return 0;
}

T3 陈太阳的树

很显然我们要对这些模式串建一个 AC 自动机,然后要做的就是在链上跑一个 AC 自动机上 dp 的板子。令 \(S\) 表示模式串总长,直接暴力做的话复杂度是 \(O(qn|\Sigma|S)\),显然过不去。

由于这是一个树上问题,且 \(S\) 比较小,所以考虑使用矩阵优化转移,然后用树剖或者倍增来查询。此时预处理复杂度是 \(O(nS|\Sigma|+nS^3\log n)\) 的,查询复杂度是 \(O(qS^2\log n)\),因为我们每次询问的时候是一个向量乘矩阵。

到这里因为种种原因其实已经可以通过了,在矩阵转移的时候特判一下当前位置有没有值即可。不过题解给出了一种比较神奇的处理方式:

考虑对于一个深度为 \(x\) 的点,记 \(\text{lowbit}(x)=2^j\),那么我们只预处理它跳到 \(2^0,2^1,\cdots,2^j\) 级祖先的矩阵。查询的时候先求出 LCA,然后再跳父亲即可。但是实际上这个复杂度并没有优化多少。

我们现在希望每一个数的 \(\text{lowbit}\) 尽可能小,这样预处理的复杂度就会降低。考虑给每个点深度同时加上一个值不会影响答案,所以我们通过这个来进行调整。先考虑最后一位,如果这一位上为 \(0\) 的数比为 \(1\) 的数多,给每个数加上 \(1\),这样可以保证这一位上为 \(1\) 的数至少是 \(\tfrac{n}2\)。对于后进面的每一位同理操作,每一次加上一个 \(2^i\) 即可。

显然每一次我们最劣的情况是 \(0,1\) 数量对半分,那么此时需要预处理的次数为 \(\tfrac{n}2\times 1+\frac n4\times 2+\frac n8\times 3+\cdots <2n\),所以预处理复杂度可以降到 \(O(nS^3)\)

综上我们可以在 \(O(n\log n+nS|\Sigma|+nS^3+qS^2\log n)\) 的复杂度内解决这个问题。

这里给出暴力做法的代码:

#include <bits/stdc++.h>
#define il inline

using namespace std;

const int Maxn = 5e3 + 5;
const int Mod = 998244353;
il int Add(int x, int y) {return x + y >= Mod ? x + y - Mod: x + y;} il void pls(int &x, int y) {x = Add(x, y);}
il int Del(int x, int y) {return x - y < 0 ? x - y + Mod : x - y;} il void sub(int &x, int y) {x = Del(x, y);}
il int qpow(int a, int b, int P = Mod) {int res = 1; for(; b; a = 1ll * a * a % P, b >>= 1) if(b & 1) res = 1ll * res * a % P; return res;}
il int Inv(int a) {return qpow(a, Mod - 2);}
template <typename T> il void chkmax(T &x, T y) {x = (x >= y ? x : y);}
template <typename T> il void chkmin(T &x, T y) {x = (x <= y ? x : y);}

il void IOS() {ios::sync_with_stdio(0); cin.tie(0), cout.tie(0);}
il void File() {freopen("in.txt", "r", stdin); freopen("out.txt", "w", stdout);}
bool Beg;

int n, m, q;
int head[Maxn], edgenum;
struct node {
	int nxt, to; string s;
}edge[Maxn];

void add(int u, int v, string s) {
	edge[++edgenum] = {head[u], v, s}; head[u] = edgenum;
	edge[++edgenum] = {head[v], u, s}; head[v] = edgenum;
}

string t[Maxn];

struct AC_Automaton {
	int son[27], fail, flg;
}tr[45];
int tot = 1;
namespace ACAM {
	void insert(string s) {
		int u = 1;
		for(int i = 0; i < s.size(); i++) {
			int ch = s[i] - 'a';
			if(!tr[u].son[ch]) tr[u].son[ch] = ++tot;
			u = tr[u].son[ch];
		}
		tr[u].flg = 1;
	}
	queue <int> q;
	void build() {
		for(int i = 0; i < 26; i++) tr[0].son[i] = 1;
		tr[1].fail = 0; q.push(1);
		while(!q.empty()) {
			int u = q.front(); q.pop();
			int fa = tr[u].fail; tr[u].flg |= tr[fa].flg;
			for(int i = 0; i < 26; i++) {
				int v = tr[u].son[i];
				if(!v) tr[u].son[i] = tr[fa].son[i];
				else tr[v].fail = tr[fa].son[i], q.push(v);
			} 
		}
		tot++;
	}
}

struct Mat {
	int a[45][45];
	Mat() {for(int i = 1; i <= tot; i++) for(int j = 1; j <= tot; j++) a[i][j] = 0;}
	Mat operator * (Mat t) {
		Mat c;
		for(int i = 1; i <= tot; i++) {
			for(int j = 1; j <= tot; j++) {
				if(!a[i][j]) continue;
				for(int k = 1; k <= tot; k++) {
					if(!t.a[j][k]) continue;
					pls(c.a[i][k], 1ll * a[i][j] * t.a[j][k] % Mod);
				}
			}
		}
		return c;
	}
};

int fa[Maxn], dep[Maxn], siz[Maxn], son[Maxn];
Mat w[Maxn], sm1[Maxn], sm2[Maxn];
void dfs1(int x, int fth, string s) {
	fa[x] = fth; dep[x] = dep[fth] + 1; siz[x] = 1;
	w[x].a[tot][tot] += s.size();
	for(int i = 1; i < tot; i++) {
		if(tr[i].flg) continue;
		for(auto ch : s) {
			int to = tr[i].son[ch - 'a'];
			if(!tr[to].flg) w[x].a[i][to]++;
			else w[x].a[i][tot]++;
		}
	}
	for(int i = head[x]; i; i = edge[i].nxt) {
		int to = edge[i].to;
		if(to == fth) continue;
		dfs1(to, x, edge[i].s);
		siz[x] += siz[to];
		if(siz[to] > siz[son[x]]) son[x] = to;
	}
}

int top[Maxn], dfn[Maxn], rnk[Maxn], idx;
void dfs2(int x, int rt) {
	top[x] = rt;
	rnk[dfn[x] = ++idx] = x;
	if(x != rt) sm1[x] = w[x] * sm1[fa[x]], sm2[x] = sm2[fa[x]] * w[x];
	else sm1[x] = sm2[x] = w[x];
	if(son[x]) dfs2(son[x], rt);
	for(int i = head[x]; i; i = edge[i].nxt) {
		int to = edge[i].to;
		if(to != son[x] && to != fa[x]) dfs2(to, to);
	} 
}

namespace SGT {
	struct node {
		Mat s1, s2;
	}t[Maxn << 2];
	#define ls(p) (p << 1)
	#define rs(p) (p << 1 | 1)
	void pushup(int p) {
		t[p].s1 = t[rs(p)].s1 * t[ls(p)].s1;
		t[p].s2 = t[ls(p)].s2 * t[rs(p)].s2;
	}
	void build(int p, int l, int r) {
		if(l == r) {
			t[p].s1 = t[p].s2 = w[rnk[l]];
			return ;
		}
		int mid = (l + r) >> 1;
		build(ls(p), l, mid), build(rs(p), mid + 1, r);
		pushup(p);
	}
	void query1(int p, int l, int r, int pl, int pr, Mat &ans) {
		if(pl > pr) return ;
		if(pl <= l && r <= pr) {ans = ans * t[p].s1; return ;}
		int mid = (l + r) >> 1;
		if(pr > mid) query1(rs(p), mid + 1, r, pl, pr, ans);
		if(pl <= mid) query1(ls(p), l, mid, pl, pr, ans);
	}
	void query2(int p, int l, int r, int pl, int pr, Mat &ans) {
		if(pl > pr) return ;
		if(pl <= l && r <= pr) {ans = ans * t[p].s2; return ;}
		int mid = (l + r) >> 1;
		if(pl <= mid) query2(ls(p), l, mid, pl, pr, ans);
		if(pr > mid) query2(rs(p), mid + 1, r, pl, pr, ans);
	}
}

Mat ret[Maxn], ans; int cnt = 0;
void solve(int u, int v) {
	for(int i = 1; i <= tot; i++) ans.a[1][i] = 0;
	ans.a[1][1] = 1;
	while(top[u] != top[v]) {
		if(dep[top[u]] > dep[top[v]]) ans = ans * sm1[u], u = fa[top[u]];
		else ret[++cnt] = sm2[v], v = fa[top[v]];
	}
	if(dep[u] > dep[v]) SGT::query1(1, 1, n, dfn[v] + 1, dfn[u], ans);
	else SGT::query2(1, 1, n, dfn[u] + 1, dfn[v], ans);
	while(cnt) ans = ans * ret[cnt--];
	cout << ans.a[1][tot] << '\n';
}

bool End;
il void Usd() {cerr << (&Beg - &End) / 1024.0 / 1024.0 << "MB " << (double)clock() * 1000.0 / CLOCKS_PER_SEC << "ms\n"; }
int main() {
	IOS(); cin >> n >> m >> q;
	for(int i = 1, u, v; i < n; i++) {
		string s; cin >> u >> v >> s;
		add(u, v, s);
	}
	for(int i = 1; i <= m; i++) cin >> t[i], ACAM::insert(t[i]);
	ACAM::build();
	dfs1(1, 0, ""); 
	dfs2(1, 1);
	SGT::build(1, 1, n);
	while(q--) {
		int u, v; cin >> u >> v;
		solve(u, v);
	}
    Usd();
	return 0;
}
posted @ 2025-05-09 17:59  UKE_Automation  阅读(43)  评论(0)    收藏  举报