1. 程式人生 > >[HDU6268]Master of Subgraph

[HDU6268]Master of Subgraph

需要 有一個 CP char tint auto pre omega reg

[HDU6268]Master of Subgraph

題目大意:

一棵\(n(n\le3000)\)個結點的樹,每個結點的權值為\(w_i\)。給定\(m(m\le10^5)\),對於任意\(i\in[1,m]\),問書中是否有一個連通子圖的權值和等於\(i\)

思路:

重心剖分。考慮處理當前處理出的以重心\(x\)為根的子樹。首先求出當前子樹的DFS序,設用\(node[i]\)表示DFS序為\(i\)的結點編號。考慮動態規劃,用\(f[i][j]\)std::bitset<M> f[N])表示包含DFS序為\(i\)的結點,是否有權值和為\(j\)的連通子圖。設當前結點為\(x\)

,枚舉子結點\(y_{1\sim k}\),則轉移方程為\(f[x]=(f[y_1]\vee f[y_2]\vee\ldots\vee f[y_k])<<w[x]\)

由於事實上對於每一個\(x\),我們並不需要知道\(f[x]\),而只需要利用它們求出\(f[root]\)的值,因此我們對於每一個\(x\)可以和上一個計算過的同級兄弟結點\(node[dfn[x]+sz[x]]\)合並。按DFS倒序枚舉每一個結點\(x\),其DFS序為\(i\)。此時的狀態轉移方程為\(f[i]=(f[i+1]<<w[x])|f[i+sz[x]]\)。時間復雜度\(\mathcal O(\frac{nm\log n}\omega)\)

源代碼:

#include<cstdio>
#include<cctype>
#include<bitset>
#include<forward_list>
inline int getint() {
    register char ch;
    while(!isdigit(ch=getchar()));
    register int x=ch^'0';
    while(isdigit(ch=getchar())) x=(((x<<2)+x)<<1)+(ch^'0');
    return
x; } constexpr int N=3001,M=1e5+1; bool vis[N]; std::forward_list<int> e[N]; std::bitset<M> ans,f[N]; int n,m,w[N],size[N],sz[N],node[N],dfn[N],root,whole,min; inline void add_edge(const int &u,const int &v) { e[u].emplace_front(v); e[v].emplace_front(u); } inline void clear() { ans.reset(); for(register int i=1;i<=n;i++) { vis[i]=false; e[i].clear(); } } void dfs_root(const int &x,const int &par) { size[x]=1; int max=0; for(auto &y:e[x]) { if(y==par||vis[y]) continue; dfs_root(y,x); size[x]+=size[y]; max=std::max(max,size[y]); } max=std::max(max,whole-size[x]); if(max<min) { min=max; root=x; } } inline void get_root(const int &x,const int &sum) { root=0; min=n+1; whole=sum; dfs_root(x,0); vis[root]=true; } void dfs(const int &x,const int &par) { sz[x]=1; dfn[x]=dfn[0]++; node[dfn[x]]=x; for(auto &y:e[x]) { if(y==par||vis[y]) continue; dfs(y,x); sz[x]+=sz[y]; } } void solve(const int &x) { dfn[0]=0; dfs(x,0); f[dfn[0]]=1; for(register int i=dfn[0]-1;~i;i--) { const int &y=node[i]; f[i]=(f[i+1]<<w[y])|f[i+sz[y]]; } ans|=f[0]; for(auto &y:e[x]) { if(vis[y]) continue; get_root(y,size[y]); solve(root); } } int main() { for(register int T=getint();T;T--) { n=getint(),m=getint(); for(register int i=1;i<n;i++) { add_edge(getint(),getint()); } for(register int i=1;i<=n;i++) { w[i]=getint(); } get_root(1,n); solve(root); for(register int i=1;i<=m;i++) { printf("%d",(int)ans[i]); } putchar('\n'); clear(); } return 0; }

[HDU6268]Master of Subgraph