1. 程式人生 > >Hdu 6268 點分治 樹上背包 bitset 優化

Hdu 6268 點分治 樹上背包 bitset 優化

scan eset using push scanf oca space false clu

給你一顆大小為n(3000)的樹,樹上每個點有點權(100000),再給你一個數m(100000)

i為1~m,問樹中是否存在一個子圖,使得權值為i.

每次solve到一個節點 用一個bitset維護所有經過它的鏈的取值(calc前要先初始化當前節點的bitset)

復雜度為nlognm/64

#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define ull unsigned long long
#define mst(a,b) memset((a),(b),sizeof(a))
#define mp(a,b) make_pair(a,b)
#define
pi acos(-1) #define pii pair<int,int> #define pb push_back const int INF = 0x3f3f3f3f; const double eps = 1e-6; const int maxn = 3e3 + 10; const int maxm = 1e5 + 10; const ll mod = 998244353; int n,m; vector<int>vec[maxn]; bool used[maxn]; int a[maxn],root,sz[maxn],son[maxn],all;
void getroot(int u,int fa) { sz[u] = 1, son[u] = 0; for(int i = 0; i < vec[u].size(); i++) { int v = vec[u][i]; if(used[v] || v == fa) continue; getroot(v,u); sz[u] += sz[v]; son[u] = max(son[u],sz[v]); } son[u] = max(son[u],all - son[u]);
if(son[u] < son[root]) root = u; } bitset<maxm>bit[maxn],ans; void calc(int u,int fa) { sz[u] = 1, bit[u] <<= a[u]; for(int i = 0; i < vec[u].size(); i++) { int v = vec[u][i]; if(used[v] || v == fa) continue; bit[v] = bit[u]; calc(v,u); sz[u] += sz[v]; bit[u] |= bit[v]; } } void solve(int u) { used[u] = true; bit[u].reset(), bit[u].set(0); calc(u,0); ans |= bit[u]; for(int i = 0; i < vec[u].size(); i++) { int v = vec[u][i]; if(used[v]) continue; root = 0; all = sz[v]; getroot(v,0); solve(root); } } int main() { #ifdef local freopen("data.txt", "r", stdin); // freopen("data.txt", "w", stdout); #endif int t; scanf("%d",&t); while(t--) { ans.reset(); scanf("%d%d",&n,&m); for(int i = 0; i <= n; i++) vec[i].clear(),used[i] = false; for(int i = 1; i < n; i++) { int u,v; scanf("%d%d",&u,&v); vec[u].push_back(v); vec[v].push_back(u); } for(int i = 1; i <= n; i++) scanf("%d",&a[i]); root = 0; son[0] = 1e9; all = n; getroot(1,0); solve(root); for(int i = 1; i <= m; i++) printf("%d",(int)ans[i]); printf("\n"); } return 0; }

Hdu 6268 點分治 樹上背包 bitset 優化