Description
Input
Output
Sample Input
5 3 4
1 2 2 1
2 3 1 3 1
2 3 4
3 5 2 2
4 3 4 2 5
2 2 2
Sample Output
2
3
0
0
Data Constraint
分析:
因为树上的边单向,显然选择在
lca
l
c
a
处是最优的。
对于特产的类别,我们考虑用一个
bitset
b
i
t
s
e
t
来维护,因为
n
n
比较大,所以只能选择线段树+树剖来算链上的特产,就不能用倍增了。
每个人带的特产数的最大值,相当于把每个人拆成
x
x
个点,与对应的
1
1
位置连边,跑最大匹配,而且一定是完全匹配,这个可以直接用hall定理来求。
hall定理:
设点集大小为
n
n
,点集大小为
m
m
,,对于
∀i∈[1,n]
∀
i
∈
[
1
,
n
]
大小为
i
i
的点集的子集,都至少与
Y
Y
集个点直接相连,满足则有完全匹配。
代码:
/**************************************************************
Problem: 5404
User: liangzihao
Language: C++
Result: Accepted
Time:9104 ms
Memory:201640 kb
****************************************************************/
#include <iostream>
#include <cstdio>
#include <cmath>
#include <bitset>
const int maxn=3e5+7;
using namespace std;
int n,m,test,x,cnt,ans;
int f[maxn][20],dep[maxn],size[maxn],top[maxn],dfn[maxn],ls[maxn];
int a[10];
struct edge{
int y,next;
}g[maxn];
bitset <1001> t[maxn*4],bit[10],h[107];
void dfs1(int x,int fa)
{
f[x][0]=fa;
size[x]=1;
dep[x]=dep[fa]+1;
for (int i=ls[x];i>0;i=g[i].next)
{
int y=g[i].y;
if (g[i].y==fa) continue;
dfs1(y,x);
size[x]+=size[y];
}
}
void dfs2(int x,int d)
{
dfn[x]=++cnt;
top[x]=d;
int c=0;
for (int i=ls[x];i>0;i=g[i].next)
{
int y=g[i].y;
if (y==f[x][0]) continue;
if (size[y]>size[c]) c=y;
}
if (!c) return;
dfs2(c,d);
for (int i=ls[x];i>0;i=g[i].next)
{
int y=g[i].y;
if ((y==f[x][0]) || (y==c)) continue;
dfs2(y,y);
}
}
void ins(int p,int l,int r,int x,int k)
{
if (l==r)
{
t[p][k]=1;
return;
}
int mid=(l+r)/2;
if (x<=mid) ins(p*2,l,mid,x,k);
else ins(p*2+1,mid+1,r,x,k);
t[p]=t[p*2]|t[p*2+1];
}
int lca(int x,int y)
{
if (dep[x]>dep[y]) swap(x,y);
int k=19,t=1<<k,d=dep[y]-dep[x];
while (d)
{
if (d>=t) d-=t,y=f[y][k];
t/=2; k--;
}
if (x==y) return x;
k=19;
while (k>=0)
{
if (f[x][k]!=f[y][k])
{
x=f[x][k];
y=f[y][k];
}
k--;
}
return f[x][0];
}
void getans(int p,int l,int r,int x,int y,int k)
{
if ((l==x) && (r==y))
{
bit[k]|=t[p];
return;
}
int mid=(l+r)/2;
if (y<=mid) getans(p*2,l,mid,x,y,k);
else if (x>mid) getans(p*2+1,mid+1,r,x,y,k);
else
{
getans(p*2,l,mid,x,mid,k);
getans(p*2+1,mid+1,r,mid+1,y,k);
}
}
void get(int x,int y,int k)
{
bit[k].reset();
while (top[x]!=top[y])
{
getans(1,1,n,dfn[top[y]],dfn[y],k);
y=f[top[y]][0];
}
getans(1,1,n,dfn[x],dfn[y],k);
}
int calc(int x)
{
int sum=0;
for (int i=x;i;i-=i&(-i)) sum++;
return sum;
}
int main()
{
scanf("%d%d%d",&n,&m,&test);
for (int i=2;i<=n;i++)
{
scanf("%d",&x);
g[i].y=i;
g[i].next=ls[x];
ls[x]=i;
}
dfs1(1,0);
dfs2(1,0);
for (int j=1;j<20;j++)
{
for (int i=1;i<=n;i++) f[i][j]=f[f[i][j-1]][j-1];
}
for (int i=1;i<=n;i++)
{
scanf("%d",&x);
ins(1,1,n,dfn[i],x);
}
for (int i=1;i<=test;i++)
{
scanf("%d",&x);
for (int j=1;j<=x;j++) scanf("%d",&a[j]);
int d=a[1];
for (int j=2;j<=x;j++) d=lca(d,a[j]);
for (int j=1;j<=x;j++) get(d,a[j],j);
for (int i=0;i<(1<<x);i++) h[i].reset();
ans=0x3f3f3f3f;
for (int i=1;i<(1<<x);i++)
{
int s=i&(-i);
int k=trunc(log(s+0.5)/log(2));
h[i]=h[i-s]|bit[(k+1)];
ans=min(ans,(int)h[i].count()/calc(i));
}
printf("%d\n",ans*x);
}
}