##Description
##Solution
我们发现颜色种类不多,只有1000种
因此我们可以用bitset来维护颜色集合。
我们将这棵树轻重链剖分,用线段树维护链的颜色集合(空间为O(N*1000/32)),若倍增的话空间要多乘上log。
当我们需要查询一条链时,由于没有修改,我们大可以直接记录每个点到所在重链顶的颜色集合,这样原本log^2的时间复杂度就变成log的了。
现在考虑我们求出了每个人的颜色集合后怎么做。
由于最终每个人带的特产数相等,答案可以写成t*c的形式
我们二分这个t(每个人带的特产数),然后将每个人拆成t个点,对应的向特产连边,要求必须完美匹配。
(用网络流的话就不用拆点直接改容量,判断是否满流即可)
然而我们有Hall定理
大概就是一个二分图有完美匹配必须满足左边任意选出若干个节点(设为K),跟这些节点有连边的右边节点的点数必须大于等于K
我们发现二分的这个t实际上就是将左边点集复制了t次,右边的连边是不变的。
因此我们2^c枚举左边的点集,答案就是 m i n ( F ( S ) ∣ S ∣ ) min({F(S)\over |S|}) min(∣S∣F(S)),其中S为我们选出的左边的点集,F为与这个点集有连边的右边点集合大小。
这个用我们刚才bitset直接求并,调用count函数即可。
复杂度是
O
(
1000
/
32
∗
N
log
n
)
O(1000/32*N\log n)
O(1000/32∗Nlogn)
##Code
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <bitset>
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define fod(i,a,b) for(int i=a;i>=b;i--)
#define N 300005
#define LL long long
using namespace std;
typedef bitset<1000> bt;
int n,m,q,m1,sz[N],dep[N],ft[N][20],fs[N],nt[N],dt[N],dfn[N],top[N],n1,w[N],t[2*N][2],dfw[N],d[N],ask[6],son[N],ans;
bt vl[N],bs[2*N],qs[6],now;
void link(int x,int y)
{
nt[++m1]=fs[x];
dt[fs[x]=m1]=y;
}
void dfs(int k)
{
dep[k]=dep[ft[k][0]]+1;
sz[k]=1;
for(int i=fs[k];i;i=nt[i])
{
int p=dt[i];
dfs(p);
sz[k]+=sz[p];
son[k]=(sz[p]>sz[son[k]])?p:son[k];
}
}
void build(int k,int l,int r)
{
if(l==r) bs[k][w[dfw[l]]-1]=1;
else
{
int mid=(l+r)>>1;
t[k][0]=++n1,build(n1,l,mid);
t[k][1]=++n1,build(n1,mid+1,r);
bs[k]=bs[t[k][0]]|bs[t[k][1]];
}
}
void make(int k)
{
dfw[dfn[k]=++dfn[0]]=k;
if(son[k])
{
top[son[k]]=top[k];
vl[son[k]]=vl[son[k]]|vl[k];
make(son[k]);
for(int i=fs[k];i;i=nt[i])
{
int p=dt[i];
if(p!=son[k])
{
top[p]=p;
make(p);
}
}
}
}
void find(int k,int l,int r,int x,int y)
{
if(x>r||y<l||x>y) return;
if(x<=l&&r<=y) d[++d[0]]=k;
else
{
int mid=(l+r)/2;
find(t[k][0],l,mid,x,y),find(t[k][1],mid+1,r,x,y);
}
}
void query(int i,int f)
{
int k=ask[i];
while(top[k]!=top[f])
{
qs[i]=qs[i]|vl[k];
k=ft[top[k]][0];
}
d[0]=0;
find(1,1,n,dfn[f],dfn[k]);
fo(j,1,d[0]) qs[i]=qs[i]|bs[d[j]];
}
int lca(int x,int y)
{
if(dep[y]<dep[x]) swap(x,y);
for(int j=19;dep[y]>dep[x];)
{
while(j&&dep[ft[y][j]]<dep[x]) j--;
y=ft[y][j];
}
for(int j=19;x!=y;)
{
while(j&&ft[y][j]==ft[x][j]) j--;
x=ft[x][j],y=ft[y][j];
}
return x;
}
void get(int k,int m,int s)
{
if(k>m)
{
if(s) ans=min(ans,(int)now.count()/s);
}
else
{
get(k+1,m,s);
bt ls=now;
now=now|qs[k];
get(k+1,m,s+1);
now=ls;
}
}
int main()
{
freopen("party.in","r",stdin);
freopen("party.out","w",stdout);
cin>>n>>m>>q;
n1=1;
fo(i,2,n)
{
scanf("%d",&ft[i][0]);
link(ft[i][0],i);
}
fo(i,1,n)
{
scanf("%d",&w[i]);
vl[i][w[i]-1]=1;
}
dfs(1);
top[1]=1,n1=1;
make(1);
build(1,1,n);
fo(j,1,19)
fo(i,1,n) ft[i][j]=ft[ft[i][j-1]][j-1];
fo(t,1,q)
{
int c,anc;
scanf("%d",&c);
fo(i,1,c) scanf("%d",&ask[i]);
anc=ask[1];
fo(i,2,c) anc=lca(anc,ask[i]);
fo(i,1,c) qs[i].reset(),query(i,anc);
ans=1000000;
get(1,c,0);
printf("%d\n",ans*c);
}
}