点击这里查看原题
考虑到n很小,对于树上每个点,选择它便会同时选择它的所有祖先,因此可以对每个点维护一个并查集,询问时做并查集合并即可。
复杂度O(nm+nk)。
不知道为何,我的get函数不加inline就会TLE,加上立马就过了,因为这个问题调了好几个小时。
/*
User:Small
Language:C++
Problem No.:5923
*/
#include<bits/stdc++.h>
#define ll long long
#define inf 999999999
using namespace std;
const int M=1e4+5;
int f[M][505],d[505],n,m,q;
vector<int> g[M];
struct no{
int u,v;
}p[M];
inline int get(int *f,int x){
return x==f[x]?x:f[x]=get(f,f[x]);
}
inline void join(int *f,int x,int y){
x=get(f,x),y=get(f,y);
f[y]=x;
}
void dfs(int u,int fa){
for(int i=1;i<=n;i++) f[u][i]=f[fa][i];
join(f[u],p[u].u,p[u].v);
vector<int>::iterator it;
for(it=g[u].begin();it!=g[u].end();it++)
dfs(*it,u);
}
inline void solve(){
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++) g[i].clear();
for(int i=2;i<=m;i++){
int x;
scanf("%d",&x);
g[x].push_back(i);
}
for(int i=1;i<=m;i++)
scanf("%d%d",&p[i].u,&p[i].v);
for(int i=1;i<=n;i++) f[0][i]=i;
dfs(1,0);
scanf("%d",&q);
while(q--){
int k,x,res=0;
scanf("%d",&k);
for(int i=1;i<=n;i++) d[i]=f[0][i];
while(k--){
scanf("%d",&x);
for(int i=1;i<=n;i++)
join(d,i,get(f[x],i));
}
for(int i=1;i<=n;i++) if(d[i]==i) res++;
printf("%d\n",res);
}
}
int main(){
freopen("data.in","r",stdin);//
int t;
scanf("%d",&t);
for(int i=1;i<=t;i++){
printf("Case #%d:\n",i);
solve();
}
return 0;
}