题面:
思路:
好像虽然思维难度不大但是考试的时候还是没有很多的人A。
首先我们可以发现既然要所有的人都要尽快到达的话那肯定是在lca的地方聚会。
然后题意就可以简化为每一个人都到lca并且只可以选择lca上的特产,所以我们要处理一条链上的颜色种数。
然后我就不会处理了,后来问了一下学长发现竟然使用bitset来维护,因为注意到颜色总共的种类只开到了1000,所以用个线段树+bitset来维护应该是没有问题的,如果怕这样会卡时间的话可以预处理每一条链上的颜色的集合的bitset前缀和,然后跳链的时候就没有必要再用一次线段树了,只是后面最后的一条链还要用一次线段树。
然后我们来考虑怎么来求最大的特产数,注意到每一个人选择的特产的种数是要相同的,假设每一个人选择的特产是
种,那么答案就是
,相当于每一个人都拆成了
点,然后人和特产之间连边跑二分图匹配,但是要求必须是完美匹配,这个时候Hall定理就要派上用场了,左边的任何一个子集都要满足和右边的相邻的点数大于子集大小,此时
的意义就相当是把左边的点集复制了
遍,所以答案很明显就是
了。
#include<bits/stdc++.h>
#define REP(i,a,b) for(int i=a;i<=b;++i)
typedef long long ll;
using namespace std;
void File(){
freopen("20180624T2_modify.in","r",stdin);
freopen("20180624T2_modify.out","w",stdout);
}
template<typename T>
void read(T &x){
T _=0,mul=1;
char __=getchar();
while(!isdigit(__)){
if(__=='-')mul=-1;
__=getchar();
}
while(isdigit(__))_=(_<<1)+(_<<3)+(__^'0'),__=getchar();
x=_*mul;
}
template<typename T>
void write(T x,char c){
if(x==0){
putchar('0');
putchar(c);
return;
}
if(x<0){putchar('-');x=-x;}
T len=1,y=10;
while(y<=x)y=(y<<3)+(y<<1),++len;
while(len--){
y/=10;
putchar(x/y+48);
x%=y;
}
putchar(c);
}
const int inf=0x3f3f3f3f;
const int maxn=3e5+10;
const int maxm=1000+10;
int n,m,q,to[maxn],las[maxn],beg[maxn],cnte;
int fa[maxn],son[maxn],dep[maxn],siz[maxn],top[maxn],dfn[maxn],cnt_dfn;
void add(int u,int v){las[++cnte]=beg[u]; beg[u]=cnte; to[cnte]=v;}
int a[maxn],co[maxn];
bitset<maxm>col[maxn<<2],sum[2][maxn];
void dfs1(int u){
siz[u]=1;
dep[u]=dep[fa[u]]+1;
for(int i=beg[u];i;i=las[i]){
dfs1(to[i]);
siz[u]+=siz[to[i]];
if(siz[to[i]]>siz[son[u]])
son[u]=to[i];
}
}
void dfs2(int u,int t){
sum[0][u][a[u]]=sum[1][u][a[u]]=1;
if(u!=t)sum[0][u]|=sum[0][fa[u]];
top[u]=t;
dfn[u]=++cnt_dfn;
if(son[u]){
dfs2(son[u],t);
sum[1][u]|=sum[1][son[u]];
}
for(int i=beg[u];i;i=las[i]){
if(to[i]==son[u])continue;
dfs2(to[i],to[i]);
}
}
struct Segment_Tree{
#define mid ((l+r)>>1)
#define lc rt<<1
#define rc rt<<1|1
#define lson lc,l,mid
#define rson rc,mid+1,r
void build(int rt,int l,int r){
if(l==r){col[rt][co[l]]=1; return;}
build(lson); build(rson);
col[rt]=col[lc]|col[rc];
}
bitset<maxm> query(int rt,int l,int r,int L,int R){
if(L<=l && r<=R)return col[rt];
if(L<=mid && R>=mid+1)return query(lson,L,R)|query(rson,L,R);
if(L<=mid)return query(lson,L,R);
else return query(rson,L,R);
}
}T;
void init(){
read(n); read(m); read(q);
REP(i,2,n){
read(fa[i]);
add(fa[i],i);
}
REP(i,1,n)read(a[i]);
dfs1(1);
dfs2(1,1);
REP(i,1,n)co[dfn[i]]=a[i];
T.build(1,1,n);
}
int get_lca(int u,int v){
while(top[u]!=top[v]){
if(dep[top[u]]<dep[top[v]])swap(u,v);
u=fa[top[u]];
}
return dep[u]<dep[v] ? u : v;
}
bitset<maxm>get_S(int u,int an){
bitset<maxm>ret;
while(top[u]!=top[an]){
ret|=sum[0][u];
u=fa[top[u]];
}
ret|=T.query(1,1,n,dfn[an],dfn[u]);
return ret;
}
void solve(){
int c,lca,b[6],ans=inf;
bitset<maxm>S[6];
read(c);
REP(i,1,c)read(b[i]);
lca=get_lca(b[1],b[2]);
REP(i,3,c)lca=get_lca(lca,b[i]);
REP(i,1,c)S[i]=get_S(b[i],lca);
REP(S0,1,(1<<c)-1){
bitset<maxm>t;
REP(i,1,c)if((1<<(i-1))&S0)
t|=S[i];
ans=min(ans,(int)(t.count()/__builtin_popcount(S0)));
}
write(ans*c,'\n');
}
int main(){
File();
init();
REP(i,1,q)solve();
return 0;
}