题解:P2465 [SDOI2008] 山贼集团
Claire0918 · · 题解
注意到
直接枚举是
将复杂度降到了枚举子集的
合并子树后仅需讨论
Code:
#include<bits/stdc++.h>
#define mem(a, v) memset(a, v, sizeof(a))
using namespace std;
const int maxn = 100 + 10, maxk = 12;
struct{
int v, nex;
} edge[maxn << 1];
int n, k, m;
int a[maxn][maxk + 10], b[1 << maxk], f[maxn][1 << maxk], g[1 << maxk];
int head[maxn], top = 0;
inline void add(int u, int v, bool o = true){
edge[++top].v = v, edge[top].nex = head[u], head[u] = top, o && (add(v, u, false), 1538);
}
inline void dfs(int u, int fa){
mem(f[u], -0x3f), f[u][0] = 0;
for (int i = head[u]; i; i = edge[i].nex){
const int v = edge[i].v;
if (v != fa){
dfs(v, u), mem(g, -0x3f);
for (int sta = 0; sta < 1 << k; sta++){
for (int st = sta;;st = st - 1 & sta){
g[sta] = max(g[sta], f[u][st] + f[v][sta ^ st]);
if (!st){
break;
}
}
}
for (int sta = 0; sta < 1 << k; sta++){
f[u][sta] = g[sta];
}
}
}
for (int i = 1; i <= k; i++){
for (int sta = 0; sta < 1 << k; sta++){
(sta >> i - 1 & 1) && (f[u][sta] = max(f[u][sta], f[u][sta ^ 1 << i - 1] - a[u][i]));
}
}
for (int sta = 0; sta < 1 << k; sta++){
for (int st = sta;;st = st - 1 & sta){
f[u][sta] += b[st];
if (!st){
break;
}
}
}
}
int main(){
scanf("%d %d", &n, &k);
for (int i = 1; i < n; i++){
int u, v;
scanf("%d %d", &u, &v), add(u, v);
}
for (int i = 1; i <= n; i++){
for (int j = 1; j <= k; j++){
scanf("%d", &a[i][j]);
}
}
scanf("%d", &m);
for (int i = 1; i <= m; i++){
int v, k, x = 0;
scanf("%d %d", &v, &k);
for (int u; k--; scanf("%d", &u), x |= 1 << u - 1);
b[x] += v;
}
dfs(1, 0);
printf("%d\n", f[1][(1 << k) - 1]);
return 0;
}