1. 程式人生 > >[樹形依賴多重揹包] BZOJ 4910 [Sdoi2017] 蘋果樹

[樹形依賴多重揹包] BZOJ 4910 [Sdoi2017] 蘋果樹

首先解決依賴揹包
如果是0/1揹包,按照後序遍歷dp,根據選或不選決策
現在是多重揹包,那麼這個點只留一個,剩下的變成一個新點掛上去,這樣仍然滿足依賴關係,
轉移的時候多重揹包用單調對列優化

可以發現如果除了最長的一條鏈,剩餘最多K
因為權值為正 那麼最長鏈必然連到葉子,剩餘必然取K個(除非不足K個)
那麼我們列舉葉子 然後兩邊總共取出K個,列舉兩邊分別選幾個
兩邊需要兩次兒子順序不同的後序遍歷
複雜度O(nK)
被卡常,我把部分分特判了才過TAT

#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<vector> #include<cstring> #define cl(x) memset(x,0,sizeof(x)) #define pb push_back using namespace std; typedef long long ll; inline char nc(){ static char buf[100000],*p1=buf,*p2=buf; return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++; } inline void read(int
&x){ char c=nc(),b=1; for (;!(c>='0' && c<='9');c=nc()) if (c=='-') b=-1; for (x=0;c>='0' && c<='9';x=x*10+c-'0',c=nc()); x*=b; } const int N=40005; const int KK=500005; const int NK=51000000; struct edge{ int u,v,next; }G[N<<1]; int head[N],inum; inline void add(int u,int
v,int p){ G[p].u=u; G[p].v=v; G[p].next=head[u]; head[u]=p; } int a[N],v[N]; #define V G[p].v int n,K; int ncnt,pos[N]; int lst1[N],lst2[N],pnt; int pre1[N],pre2[N],back1[N],back2[N]; int size[N]; int f1[NK],f2[NK]; int leaf[N]; int val[N],depth[N]; inline void dfs1(int u){ pre1[u]=pnt+1; size[u]=1; for (int p=head[u];p;p=G[p].next){ val[V]=val[u]+v[V],depth[V]=depth[u]+1; dfs1(V); size[u]+=size[V]; } lst1[++pnt]=u; back1[u]=pnt; } inline void dfs2(int u){ pre2[u]=pnt+1; vector<int> v; for (int p=head[u];p;p=G[p].next) v.pb(V); for (int i=v.size()-1;~i;i--) dfs2(v[i]); lst2[++pnt]=u; back2[u]=pnt; } int Q[KK],l,r; int Q2[KK]; #define F(i,j) (ff[(i)*(K+1)+(j)]) inline int max(int a,int b){ return a>b?a:b; } inline void DP(int *ff,int *lst,int *pre){ F(0,0)=0; for (int k=1;k<=K;k++) F(0,k)=-1<<29; for (int i=1;i<=ncnt;i++){ int x=lst[i]; int *f=ff+i*(K+1),*g=ff+(i-1)*(K+1),*t=ff+(pre[x]-1)*(K+1); //for (int k=0;k<=K;k++) f[k]=t[k]; memcpy(f,t,sizeof(int)*(K+1)); if (a[x]==0) continue; if (a[x]==1){ for (int k=1;k<=K;k++) f[k]=max(f[k],g[k-1]+v[x]); }else{ l=r=-1; Q[++r]=0; Q2[r]=g[Q[r]]-Q[r]*v[x]; for (int j=1;j<=K;j++){ while (l<r && Q[l+1]<j-a[x]) l++; if (l<r) f[j]=max(f[j],Q2[l+1]+j*v[x]); int tmp=g[j]-j*v[x]; while (l<r && tmp>=Q2[r]) r--; Q[++r]=j; Q2[r]=tmp; } } } } namespace Work{ inline bool cmp(int x,int y){ return v[x]>v[y]; } int idx[N]; inline void Solve(){ for (int i=1;i<=n;i++) idx[i]=i,a[i]+=a[pos[i]]; a[1]--; int x=K+1,ans=v[1]; sort(idx+1,idx+n+1,cmp); for (int i=1;i<=n;i++){ int t=min(x,a[idx[i]]); x-=t; ans+=v[idx[i]]*t; if (!x) break; } printf("%d\n",ans); } } int main(){ int T; int x,y,z; freopen("t.in","r",stdin); freopen("t.out","w",stdout); read(T); while (T--){ read(n); read(K); ll tot=0; ncnt=n; int maxv=0; for (int i=1;i<=n;i++){ read(x); read(y); read(z); tot+=y; maxv=max(maxv,x); if (x) add(x,i,++inum),leaf[x]=1; v[i]=z; a[i]=1; if (y>1) pos[i]=++ncnt,v[ncnt]=z,a[ncnt]=y-1,add(i,ncnt,++inum); } if (maxv<=1){ Work::Solve(); cl(head); inum=0; cl(leaf); cl(pos); continue; } pnt=0; val[1]=v[1]; depth[1]=1; dfs1(1); DP(f1,lst1,pre1); pnt=0; dfs2(1); DP(f2,lst2,pre2); int ans=-1<<30; for (int i=1;i<=n;i++) if (!leaf[i]){ int *f=f1+(K+1)*(pre1[i]+size[i]-2); int *g=f2+(K+1)*(pre2[i]-1); int x=min(tot-depth[i],(ll)K); for (int k=0;k<=x;k++) ans=max(ans,val[i]+f[k]+g[x-k]); } printf("%d\n",ans); cl(head); inum=0; cl(leaf); cl(pos); } return 0; }

相關推薦

[樹形依賴多重揹包] BZOJ 4910 [Sdoi2017] 蘋果樹

首先解決依賴揹包 如果是0/1揹包,按照後序遍歷dp,根據選或不選決策 現在是多重揹包,那麼這個點只留一個,剩下的變成一個新點掛上去,這樣仍然滿足依賴關係, 轉移的時候多重揹包用單調對列優化 可以發現如果除了最長的一條鏈,剩餘最多K個 因為權值為正 那

[樹上依賴多重揹包 DP] BZOJ 4910 [Sdoi2017]蘋果樹

題目 t−h≤k 的限制其實就是選一條到葉節點的鏈,然後再選k個的最大值(因為vi都大於零)。 因為 ai>1 的點,肯定是先選了第一個才會選第二個 所以可以把 ai>1 的點拆成兩個點 i′,i′′,ai′=1,ai′′=ai−1,讓 i′′

JZOJ4202. Shopping(點分治+樹形依賴+多重揹包

題意: 一顆樹,每個點代表一個物品,空間c[i]c[i],數量d[i]d[i],價值w[i]w[i],現有一個空間為mm的揹包,選樹上相互連線的物品,求最大價值 想法: 一眼樹形揹包,時間複雜度上天 f[i][j]f[i][j]表示i的子樹內,i

BZOJ.4910.蘋果樹(樹形依賴揹包 DP 單調佇列)

BZOJ 洛谷 \(shadowice\)已經把他的思路說的很清楚了,可以先看一下會更好理解? 這篇主要是對\(Claris\)題解的簡單說明。與\(shadowice\)的做法還是有差異的(比如並沒有明顯用到後序遍歷的性質),而且用這種寫法可能跑的比較輕鬆? 問題等價於樹形依賴揹包,允許一條鏈每個

BZOJ.3425.[POI2013]Polarization(DP 多重揹包)

BZOJ 洛谷 最小可到達點對數自然是把一條路徑上的邊不斷反向,也就是黑白染色後都由黑點指向白點。這樣答案就是\(n-1\)。 最大可到達點對數,容易想到找一個點\(a\),然後將其子樹分為兩部分\(x,y\),\(x\)子樹所有邊全指向\(a\),\(a\)與\(y\)子樹之間的邊全指向\(y\)。這樣答

bzoj 1812 [IOI2005] riv (樹形dp,樹上揹包

這道題比較有難度。。。首先可以想到f[i][k]表示i點的子樹中用了k個伐木場。但是這顯然沒法轉移。那麼我們加上一維, f[i][j][k]表示i點的子樹內用了k個伐木場並且上一個用的位置為j,而當前點可選可不選(看第二維的狀態),之後用子樹更新即可 合併的時候和更新的時

洛谷 P2014 選課 樹形依賴揹包

題目描述 在大學裡每個學生,為了達到一定的學分,必須從很多課程裡選擇一些課程來學習,在課程裡有些課程必須在某些課程之前學習,如高等數學總是在其它課程之前學習。現在有N門功課,每門課有個學分,每門課有一

Codeforces 815 C 樹形依賴揹包 解題報告

C. Karen and Supermarket On the way home, Karen decided to stop by the supermarket to buy some groceries. She needs to buy a lot

BZOJ 4182 Shopping (樹分治+樹上多重揹包)

題目大意:給你一顆樹,你有$m$元錢,每個節點都有一種物品,價值為$w$,代價為$c$,有$d$個,如果在$u$和$v$兩個城市都購買了至少一個物品,那麼$u,v$路徑上每個節點也都必須買至少一個物品 單調佇列陣列開小了調了2h 通過這道題,本蒟蒻終於$get$到了樹上帶權揹包的正確姿勢 合併揹包的代價

【DP】計劃11.8——(樹形依賴揹包總結)&&分數規劃思想

樹形依賴揹包指的就是一類具有樹形依賴關係的揹包問題。當選一個物品的前提是選另一件物品,而這些依賴關係構成了一個樹形關係。在容量有限的情況下,然後求最大的價值,這類問題我們就稱之為樹形依賴揹包。 樹形依賴揹包問題實際上是一類分組揹包問題,我們可以將每個點的子樹看成

動態規劃--樹形依賴揹包

樹形依賴揹包是子樹依賴父親才能產生貢獻的一類問題。 有三種種解決的辦法: 1.強制選擇當前節點,用當前的狀態去更新子樹資訊,然後再用子樹資訊更新父親。 2

hdu-1561 The more, The Better (樹形dp入門,有依賴揹包問題

The more, The Better Time Limit: 6000/2000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 4954    

樹形依賴揹包

問題大意:給出一棵樹,根節點為1,每個點有毒素和收穫。要求毒素不超過給定值的情況下使收穫最大。一個點的父親節點被選取後這個點才能被選取。 首先弄出dfs序,也記錄下每個點其子樹及自身的大小。每個點都能夠被選或不選,如果選了才會考慮它子樹。 設f[i][j]表

BZOJ 1531: [POI2005]Bank notes 多重揹包

1531: [POI2005]Bank notes Time Limit: 5 Sec  Memory Limit: 64 MBSubmit: 506  Solved: 279 [Submit][

csu1580 樹形依賴揹包模板題

題意 有一輛能載客m的車,有n個人,然後第i個人上車的條件是第a[i]個人要上車,問最多能上幾個。 (題意很簡單吧。)。 思路 首先要明確一點,這些人的依賴可能會成環,也就是說一群人要一起

BZOJ 3163 Heoi2013 Eden的新揹包問題 多重揹包

題目大意:多重揹包,多次詢問某個物品不能選擇時以某個總價錢最多能獲得多少價值 求問正解是啥QAQ 維護一個字首多重揹包和一個字尾多重揹包 每次詢問時 列舉前面選多少和後面選多少 暴力統計答案即可 時間複雜度O(n^2logn+nq) 這3E的複雜度居然只跑了600sQAQ

HDU 1561 The more, The Better(多重揹包+樹形DP)

Problem Description ACboy很喜歡玩一種戰略遊戲,在一個地圖上,有N座城堡,每座城堡都有一定的寶物,在每次遊戲中ACboy允許攻克M個城堡並獲得裡面的寶物。但由於地理位置原因,有些城堡不能直接攻克,要攻克這些城堡必須先攻克其他某一個特定的城堡。你能幫A

BZOJ 4817: [Sdoi2017]樹點塗色

prepare new 來看 rep next 結果 wap tchar end 二次聯通門 : BZOJ 4817: [Sdoi2017]樹點塗色 /* BZOJ 4817: [Sdoi2017]樹點塗色 考場上打的暴力

bzoj 4819 [Sdoi2017]新生舞會

continue net map sizeof rip 還需 mes += scanf Description 學校組織了一次新生舞會,Cathy作為經驗豐富的老學姐,負責為同學們安排舞伴。有n個男生和n個女生參加舞會 買一個男生和一個女生一起跳舞,互為舞伴。Cathy收

BZOJ 4816: [Sdoi2017]數字表格

nbsp n) stream .com zoj www. pri oid [] 二次聯通門 : BZOJ 4816: [Sdoi2017]數字表格 /* BZOJ 4816: [Sdoi2017]數字表格 莫比烏斯反演 媽呀,我