CCPC 2016 杭州 E. Master of Subgraph(點分治+bitset優化DP)
阿新 • • 發佈:2018-11-19
題目連結:http://acm.hdu.edu.cn/downloads/CCPC2018-Hangzhou-ProblemSet.pdf
題意:給定一棵有 n 個結點的樹和一個數 m,對於 i ∈ [1,m] 問是否存在一個子圖結點的權值和為 i 。
題解:一個顯然的思路是樹上做揹包,但顯然會 T。要遍歷全部子圖,考慮進行點分治,然後合併的時候用 bitset 優化揹包,時間複雜度O(nmlogn / 64),且時限給了 8s。
1 #include <bits/stdc++.h> 2 using namespace std; 3 #define ll long long 4#define ull unsigned long long 5 #define mst(a,b) memset((a),(b),sizeof(a)) 6 #define mp(a,b) make_pair(a,b) 7 #define pi acos(-1) 8 #define pii pair<int,int> 9 #define pb push_back 10 const int INF = 0x3f3f3f3f; 11 const double eps = 1e-6; 12 const int maxn = 3e3 + 10; 13 const int maxm = 1e5 + 10; 14 const ll mod = 998244353; 15 16 int n,m; 17 vector<int>vec[maxn]; 18 bool used[maxn]; 19 int a[maxn],root,sz[maxn],son[maxn],all; 20 21 void getroot(int u,int fa) { 22 sz[u] = 1, son[u] = 0; 23 for(int i = 0; i < vec[u].size(); i++) { 24 int v = vec[u][i]; 25 if(used[v] || v == fa) continue; 26 getroot(v,u); 27 sz[u] += sz[v]; 28 son[u] = max(son[u],sz[v]); 29 } 30 son[u] = max(son[u],all - son[u]); 31 if(son[u] < son[root]) root = u; 32 } 33 34 bitset<maxm>bit[maxn],ans; 35 36 void calc(int u,int fa) { 37 sz[u] = 1, bit[u] <<= a[u]; 38 for(int i = 0; i < vec[u].size(); i++) { 39 int v = vec[u][i]; 40 if(used[v] || v == fa) continue; 41 bit[v] = bit[u]; 42 calc(v,u); 43 sz[u] += sz[v]; 44 bit[u] |= bit[v]; 45 } 46 } 47 48 void solve(int u) { 49 used[u] = true; 50 bit[u].reset(), bit[u].set(0); 51 calc(u,0); 52 ans |= bit[u]; 53 for(int i = 0; i < vec[u].size(); i++) { 54 int v = vec[u][i]; 55 if(used[v]) continue; 56 root = 0; 57 all = sz[v]; 58 getroot(v,0); 59 solve(root); 60 } 61 } 62 63 int main() { 64 #ifdef local 65 freopen("data.txt", "r", stdin); 66 // freopen("data.txt", "w", stdout); 67 #endif 68 int t; 69 scanf("%d",&t); 70 while(t--) { 71 ans.reset(); 72 scanf("%d%d",&n,&m); 73 for(int i = 0; i <= n; i++) vec[i].clear(),used[i] = false; 74 for(int i = 1; i < n; i++) { 75 int u,v; 76 scanf("%d%d",&u,&v); 77 vec[u].push_back(v); 78 vec[v].push_back(u); 79 } 80 for(int i = 1; i <= n; i++) scanf("%d",&a[i]); 81 root = 0; 82 son[0] = 1e9; 83 all = n; 84 getroot(1,0); 85 solve(root); 86 for(int i = 1; i <= m; i++) printf("%d",(int)ans[i]); 87 printf("\n"); 88 } 89 return 0; 90 }