题意
n<=3e5,q<=5e4,m<=1e3
模型转换
当确定每个人能带的颜色(特产)后,就变成了一个网络流问题。
每个人向它的颜色连边,颜色向T连1容量的边。
可以二分一个答案mid,然后从S给每个人连这么多容量的边,若能跑满则存在解。因为左边5个点,可以枚举左边怎么选,求出最小割(=最大流)就行。
然而并不需要这么麻烦,容易发现上面的模型可以变为:
将一个人拆成mid个点,判断是否存在对于左侧的完备匹配。
百度一下Hall定理,发现他是存在完备匹配的充要条件。
那么,2^5枚举左边如何选择集合,假如左边x个点,右边相连有y个点,那么显然每个人不能拆为超过
y/x
y
/
x
个点。否则就不符合这组限制。
至于如何获取集合,bitset+树剖,再预处理出到链顶的前缀和。
就可以
O(nlogn⋅m/w)
O
(
n
l
o
g
n
⋅
m
/
w
)
的做了。
另外有bfs就可以求dfs序的黑科技,简直棒棒哒(妈妈再也不怕我爆栈了)
实现
#include <iostream>
#include <cstring>
#include <cstdio>
#include <bitset>
#define lowbit(x) ((x) & -(x))
using namespace std;
const int N = 3e5+10;
int n,m,q,fa[N],final[N],nex[N],to[N],tot,a[N],ww[N];
int d[N],g[N][20],top[N],size[N],hvy[N],dfn[N];
bitset<1001> bs[N],t[N*4];
void link(int x,int y) {
to[++tot] = y,nex[tot] = final[x],final[x] = tot;
}
int p[6], ans, c;
int l;
void init() {
for (int i = 1; i <= n; i++) for (int j = 1; j <= 18; j++)
g[i][j] = g[g[i][j-1]][j-1];
for (int x = n; x; x--) {
for (int i = final[x]; i; i=nex[i]) {
size[x] += size[to[i]];
if (size[to[i]] > size[hvy[x]]) hvy[x] = to[i];
}
size[x]++;
}
dfn[1] = 1;
for (int x = 1; x <= n; x++) {
if (top[x]==0) top[x] = x;
else bs[x] |= bs[fa[x]];
bs[x][a[x]] = 1;
d[x] = d[fa[x]] + 1;
int t = dfn[x] + 1;
if (hvy[x]) {
top[hvy[x]] = top[x];
dfn[hvy[x]] = t;
t += size[hvy[x]];
}
for (int i = final[x]; i; i=nex[i]) {
int y = to[i];
if (y == hvy[x]) continue;
dfn[y] = t; t+=size[y];
}
}
for (int i = 1; i <= n; i++) ww[dfn[i]] = i;
}
//change to top
int lca(int x,int y) {
while (top[x] != top[y]) {
if (d[top[x]] < d[top[y]]) swap(x,y);
x = fa[top[x]];
}
return d[x] > d[y] ? y : x;
}
void build(int x,int l,int r) {
if (l == r) {
t[x][a[ww[l]]] = 1;
return;
}
build(x*2,l,l+r>>1); build(x*2+1,(l+r>>1)+1,r);
t[x] = t[x*2] | t[x*2+1];
}
int Tl,Tr,Tg;
bitset<1001> bp[6];
void query(int x,int l,int r) {
if (r<Tl || l > Tr) return;
if (Tl<= l && r <= Tr) {
bp[Tg] |= t[x];
return;
}
query(x*2,l,l+r>>1);
query(x*2+1,(l+r>>1)+1,r);
}
void getbitset(int e) {
int x = p[e];
while (top[x] != top[l]) {
bp[e] |= bs[x];
x = fa[top[x]];
}
Tl = dfn[l], Tr = dfn[x], Tg = e;
query(1,1,n);
}
int gs[100],id[100];
bitset<1001> dt[32];
int main() {
freopen("party.in","r",stdin);
freopen("party.out","w",stdout);
cin>>n>>m>>q; if (q == 0) return 0;
for (int i = 2; i <= n; i++) {
scanf("%d",&fa[i]); g[i][0] = fa[i];
link(fa[i], i);
}
for (int i = 1; i < 32; i++) gs[i] = gs[i - lowbit(i)] + 1;
for (int i = 1; i < 6; i++) id[1<<i-1] = i;
for (int i = 1; i <= n; i++) scanf("%d",&a[i]);
init(); build(1,1,n);
for (int z = 1; z <= q; z++) {
scanf("%d",&c);
for (int i = 1; i <= c; i++) scanf("%d",&p[i]), bp[i].reset();
l = p[1]; for (int i = 1; i <= c; i++) l = lca(l, p[i]);
for (int i = 1; i <= c; i++)
getbitset(i);
int ans = 1e8;
for (int i = 1; i < (1<<c); i++) {
dt[i] = dt[i - lowbit(i)] | bp[id[lowbit(i)]];
int z = dt[i].count();
ans = min(ans, z / gs[i]);
}
printf("%d\n",ans * c);
}
}