題意:
數據範圍:
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;
}