树 树 树
正 解 部 分 \color{red}{正解部分} 正解部分
建出以 r r r 为根的 虚树, 将 关键点 按照 虚树 中的深度排序, 这样可以保证一个点的祖先全部在其前面,
设 F [ i , j ] F[i, j] F[i,j] 表示前 i i i 个点, 分为 j j j 组 的 方案数, g [ i ] g[i] g[i] 表示 i i i 到 r r r 的路径上 关键点 的个数,
因为 i i i 的祖先们必定不是在同一个组内,
所以可以这样转移: F [ i , j ] = ( i − g [ a i ] ) × F [ i − 1 , j ] + F [ i − 1 , j − 1 ] F[i, j] = (i - g[a_i])\times F[i-1, j] + F[i-1,j-1] F[i,j]=(i−g[ai])×F[i−1,j]+F[i−1,j−1], 最后 a n s = ∑ i = 1 M F [ k , i ] ans =\sum\limits_{i=1}^M F[k,i] ans=i=1∑MF[k,i] .
实 现 部 分 \color{red}{实现部分} 实现部分
#include<bits/stdc++.h>
#define reg register
int read(){
char c;
int s = 0, flag = 1;
while((c=getchar()) && !isdigit(c))
if(c == '-'){ flag = -1, c = getchar(); break ; }
while(isdigit(c)) s = s*10 + c-'0', c = getchar();
return s * flag;
}
const int mod = 1e9 + 7;
const int maxn = 1e5 + 5;
int N;
int K;
int M;
int R;
int K_;
int Q_;
int hs_cnt;
int dfs_tim;
int num0[2];
int a[maxn];
int b[maxn];
int g[maxn];
int Hs[maxn];
int dfn[maxn];
int stk[maxn];
int dep0[maxn];
int F[maxn][305];
int Fk[maxn][20];
int head[2][maxn];
bool vis[maxn];
bool used[maxn];
struct Edge{ int nxt, to; } edge[2][maxn << 1];
void Add(int from, int to, int id){ edge[id][++ num0[id]] = (Edge){ head[id][from], to }; head[id][from] = num0[id]; }
void DFS_0(int k, int fa){ //
dfn[k] = ++ dfs_tim; dep0[k] = dep0[fa] + 1;
for(reg int i = 1; i <= 19; i ++) Fk[k][i] = Fk[Fk[k][i-1]][i-1];
for(reg int i = head[0][k]; i; i = edge[0][i].nxt){ int to = edge[0][i].to; if(to == fa) continue ; Fk[to][0] = k; DFS_0(to, k); }
}
int Lca(int a, int b){ //
if(dep0[a] < dep0[b]) std::swap(a, b);
for(reg int i = 19; i >= 0; i --) if(dep0[Fk[a][i]] >= dep0[b]) a = Fk[a][i]; if(a == b) return a;
for(reg int i = 19; i >= 0; i --) if(Fk[a][i] != Fk[b][i]) a = Fk[a][i], b = Fk[b][i]; return Fk[a][0];
}
bool cmp_1(int a, int b){ return dfn[a] < dfn[b]; }
bool cmp_2(int a, int b){ return g[a] < g[b]; }
int Dis(int u, int v){ return dep0[u] + dep0[v] - 2*dep0[Lca(u, v)]; }
void Build(){
std::sort(a+1, a+K+1, cmp_1);
int top = 0; stk[++ top] = 1;
for(reg int i = 1 + (a[1]==1); i <= K; i ++){
int u = stk[top], v = a[i];
int p = Lca(u, v);
if(!vis[p]) Hs[++ hs_cnt] = p, vis[p] = 1;
if(p == u) stk[++ top] = v;
else{
while(dep0[stk[top-1]] >= dep0[p] && top >= 2)
Add(stk[top-1], stk[top], 1), Add(stk[top], stk[top-1], 1), top --;
if(stk[top] != p) Add(p, stk[top], 1), Add(stk[top], p, 1), stk[top] = p;
stk[++ top] = v;
}
}
for(reg int i = 1; i <= top; i ++)
if(i != top) Add(stk[i], stk[i+1], 1), Add(stk[i+1], stk[i], 1);
}
void DFS(int k, int fa){
g[k] = g[fa] + used[fa];
for(reg int i = head[1][k]; i; i = edge[1][i].nxt){ int to = edge[1][i].to; if(to == fa) continue ; DFS(to, k); }
}
void Dp(){
std::sort(b+1, b+K_+1, cmp_2);
F[0][0] = 1;
for(reg int i = 1; i <= K_; i ++)
for(reg int j = 1; j <= M; j ++) F[i][j] = 0;
for(reg int i = 1; i <= K_; i ++)
for(reg int j = 1; j <= M; j ++){
F[i][j] = F[i-1][j-1];
if(j > g[b[i]]) F[i][j] = (F[i][j] + 1ll*F[i-1][j]*(j-g[b[i]])%mod) % mod;
}
int Ans = 0;
for(reg int i = 1; i <= M; i ++) Ans = (Ans + F[K_][i]) % mod;
printf("%d\n", Ans);
}
void Work(){
K = read(), M = read(), R = read();
int flag = 0; hs_cnt = 0;
for(reg int i = 1; i <= K; i ++){
b[i] = a[i] = read();
used[a[i]] = vis[a[i]] = 1;
Hs[++ hs_cnt] = a[i];
if(a[i] == R) flag = 1;
}
K_ = K;
if(!flag) a[++ K] = R, Hs[++ hs_cnt] = R, vis[R] = 1;
Build(); DFS(R, 0); Dp();
num0[1] = 0; for(reg int i = 1; i <= hs_cnt; i ++) head[1][Hs[i]] = used[Hs[i]] = vis[Hs[i]] = 0;
}
int main(){
freopen("tree.in", "r", stdin);
freopen("tree.out", "w", stdout);
N = read(); Q_ = read();
for(reg int i = 1; i < N; i ++){ int u = read(), v = read(); Add(u, v, 0), Add(v, u, 0); }
DFS_0(1, 0); while(Q_ --) Work();
return 0;
}