版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/XLno_name/article/details/81747107
题意:
数据范围:
Analysis
首先考虑办聚会的城市,由于道路是单向的,不难发现该城市就是这
个城市的
.
考虑选择礼品的限制如何解决,思考一下发现是对于每一个礼品分配城市,考虑网络流解决.
至于所有城市的礼品数一样我们可以二分限制最大流,判断是否能满流即可。
我考场上考虑到这里,事实上已经能拿到
分了,本来想能不能最大流转最小割做
,发现并不行。
运用
定理,每一次二分,可以相当于把每个城市拆成
个点,两边二分图匹配,只要知道是否有完备匹配即可,那么根据
定理,两边有完备匹配的必要条件是:
左部任意一个子集相邻的点都
子集大小。
那么每一个子集都找出它最多能够给每个城市分配多少礼品,即右方相邻点数目除以子集大小。
至于每一个点到聚会城市的颜色数目,颜色种类只有
,直接线段树维护一下
,用树链剖分解决,预处理每一个点到链顶的
,复杂度可以做到
Code
# include<cstdio>
# include<cstring>
# include<algorithm>
# include<bitset>
using namespace std;
const int N = 3e5 + 5;
const int M = 1e3 + 5;
bitset <M> c[N << 2],s[N],a[15],las;
int in[N],top[N],fa[N],dep[N],siz[N],son[N],id[N];
int v[N],to[N],nx[N],st[N],z[15];
int n,m,tot,q;
inline int read()
{
int x = 0; char ch = getchar();
for (; ch < '0' || ch > '9' ; ch = getchar());
for (; ch >= '0' && ch <= '9' ; ch = getchar()) x = x * 10 + ch - '0';
return x;
}
void add(int u,int v) { to[++tot] = v,nx[tot] = st[u],st[u] = tot; }
inline void build(int x,int l,int r)
{
if (l == r) { c[x][v[id[l]]] = 1; return; }
int mid = (l + r) >> 1;
build(x << 1,l,mid); build(x << 1 | 1,mid + 1,r);
c[x] = c[x << 1] | c[x << 1 | 1];
}
inline void qry(int x,int l,int r,int l1,int r1,int p)
{
if (l >= l1 && r <= r1) { a[p] |= c[x]; return; }
int mid = (l + r) >> 1;
if (l1 <= mid) qry(x << 1,l,mid,l1,r1,p);
if (r1 > mid) qry(x << 1 | 1,mid + 1,r,l1,r1,p);
}
void dfs(int x)
{
siz[x] = 1;
for (int i = st[x] ; i ; i = nx[i])
{
dfs(to[i]),siz[x] += siz[to[i]];
if (siz[to[i]] > siz[son[x]]) son[x] = to[i];
}
}
void dfs1(int x,int f,int t)
{
in[x] = ++tot,id[tot] = x,top[x] = t;
if (x != t) s[x] = s[f]; s[x][v[x]] = 1;
if (son[x]) dfs1(son[x],x,t);
for (int i = st[x] ; i ; i = nx[i])
if (to[i] != son[x]) dfs1(to[i],x,to[i]);
}
inline int find(int x,int y)
{
while (top[x] != top[y])
{
if (dep[top[x]] < dep[top[y]]) swap(x,y);
x = fa[top[x]];
}
return dep[x] < dep[y] ? x : y;
}
inline void solve(int x,int y,int p)
{
while (top[x] != top[y])
{
a[p] |= s[x];
x = fa[top[x]];
}
qry(1,1,n,in[y],in[x],p);
}
int main()
{
n = read(),m = read(),q = read();
for (int i = 2 ; i <= n ; ++i) fa[i] = read(),dep[i] = dep[fa[i]] + 1,add(fa[i],i);
for (int i = 1 ; i <= n ; ++i) v[i] = read();
tot = 0,dfs(1);
dfs1(1,0,1); build(1,1,n);
while (q--)
{
int num = read();
for (int i = 1 ; i <= num ; ++i) z[i] = read(),a[i].reset();
int lca = z[1];
for (int i = 2 ; i <= num ; ++i) lca = find(lca,z[i]);
for (int i = 1 ; i <= num ; ++i) solve(z[i],lca,i);
int ans = M;
for (int i = 1 ; i < (1 << num) ; ++i)
{
int cnt = 0; las.reset();
for (int j = 1 ; j <= num ; ++j)
if (i & (1 << (j - 1))) ++cnt,las |= a[j];
ans = min(ans,(int)las.count() / cnt);
}
printf("%d\n",ans * num);
}
return 0;
}