<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      DP優(yōu)化——樹上依賴性背包&P6326 Shopping

      P6326 Shopping

      題意等價于要買一個連通塊。

      首先如果我們能求出一個 dp 數(shù)組:
      \(f_{i,j}\) 表示 \(i\) 子樹內(nèi),有 \(j\) 元,一定要選 \(i\),能得到的最大價值。
      那么 \(f_{1,m}\) 就是一定選根的答案。
      然后點(diǎn)分治即可。

      接下來就是怎么在合理的復(fù)雜度內(nèi)求出 dp 數(shù)組。
      直接背包顯然不行,因為這不是一個普通的樹形背包,他的第二維跟子樹大小無關(guān),所以合并子樹的復(fù)雜度是單次 \(O(m^2)\),總復(fù)雜度是 \(O(nm^2)\)

      然后就誕生了一種很厲害的科技——樹上依賴性背包
      因為選兒子就一定要選父親,所以管他叫這個名字。
      具體做法是:
      設(shè) \(f_{i,j}\) 表示考慮 dfn 位于 \([i,n]\) 中的點(diǎn),有 \(j\) 元錢能得到的最大價值。
      下面設(shè)根為 \(1\)
      因為根是 dfn 最小的點(diǎn),它一定要選,特判一下。
      接下來考慮 \(dfn=2\) 的點(diǎn),不妨設(shè)為 \(2\),他一定是 \(1\) 的兒子,他有兩種選擇:

      1. 不選,那他子樹內(nèi)的點(diǎn)都不能選,而眾所周知,子樹內(nèi)的點(diǎn)的 dfn 是連續(xù)的一段區(qū)間,那么轉(zhuǎn)移就是:\(f_{2 + Size_2,j} \to f_{2,j}\)
        此時剩下的問題相當(dāng)是把 \(2\) 這棵子樹去掉了,仍然是一棵樹,并且 dfn 也是一個后綴。
        并且如果在剩下的這棵樹內(nèi)選擇了一個連通塊,那么放到原樹內(nèi)選出的也是一個連通塊。
        所以他是一個子問題。
      2. 選,轉(zhuǎn)移是:\(max_{1\le k \le d_2}(f_{3,j-c_2\times k} + w_2\times k) \to f_{2,j}\)
        這個轉(zhuǎn)移本質(zhì)是多重背包,可以用二進(jìn)制拆分優(yōu)化到 \(O(\log d)\),也可以用單調(diào)隊列優(yōu)化到均攤 \(O(1)\)
        此時 \(1,2\) 構(gòu)成了一個連通塊,我們把它視為新的根,原本 \(1,2\) 的子樹接到這個新的根上。
        那么構(gòu)成的仍然是一棵樹,dfn 是一個后綴,且如果在這棵新樹里選出了一個連通塊,那么放到原樹上也是一個連通塊。
        所以它也是一個子問題。
        然后把新的根當(dāng)根繼續(xù)考慮 \(dfn=3\) 的點(diǎn)。

      答案是 \(f_{1,m}\)

      這個 dp 是 \(O(nm\log d)\) 或者 \(O(nm)\) 的。
      總復(fù)雜度乘一個點(diǎn)分治的 \(O(\log n)\) 即可。

      #include<bits/stdc++.h>
      using namespace std;
      const int N=500+5,M=4000+5,inf=0x3f3f3f3f3f3f3f3f;
      inline int read(){
          int w = 1, s = 0;
          char c = getchar();
          for (; c < '0' || c > '9'; w *= (c == '-') ? -1 : 1, c = getchar());
          for (; c >= '0' && c <= '9'; s = 10 * s + (c - '0'), c = getchar());
          return s * w;
      }
      int n,m,ans,w[N],c[N],d[N];
      int tot,head[N],to[N<<1],Next[N<<1];
      void add(int u,int v){
      	to[++tot]=v,Next[tot]=head[u],head[u]=tot;
      } 
      
      int rt,sum,Size[N],maxn[N],rev[N],num,f[N][M],g[M];
      bool vis[N];
      void Get_zx(int u,int fa){
      	Size[u]=1;
      	maxn[u]=0;
      	for(int i=head[u];i;i=Next[i]){
      		int v=to[i];
      		if(vis[v]||v==fa) continue;
      		Get_zx(v,u);
      		Size[u]+=Size[v];
      		maxn[u]=max(maxn[u],Size[v]);
      	}
      	maxn[u]=max(maxn[u],sum-Size[u]);
      	if(maxn[u]<maxn[rt]) rt=u;
      }
      void dfs(int u,int fa){
      	rev[++num]=u;
      	Size[u]=1;
      	for(int i=head[u];i;i=Next[i]){
      		int v=to[i];
      		if(vis[v]||v==fa) continue;
      		dfs(v,u);
      		Size[u]+=Size[v];
      	}
      }
      
      void calc(){
      	for(int i=1;i<=num+1;i++) for(int j=0;j<=m;j++) f[i][j]=(i==num+1)?0:-inf;
      	for(int i=num;i>=1;i--){
      		int u=rev[i],lst=d[u]-1;  //因為一定要選一個,所以在一開始就減掉 
      		vector<int> v;
      		for(int mi=1;lst>=mi;mi<<=1){
      			v.emplace_back(mi);
      			lst-=mi;
      		} 
      		if(lst) v.emplace_back(lst);
      		for(int j=0;j<=m;j++) g[j]=(j>=c[u])?(f[i+1][j-c[u]]+w[u]):-inf;  //確保至少選一個 
      		for(int x:v) for(int j=m;j>=x*c[u];j--) g[j]=max(g[j],g[j-x*c[u]]+x*w[u]);
      		for(int j=0;j<=m;j++){
      			f[i][j]=g[j];  //起碼要選一個 
      			if(i!=1) f[i][j]=max(f[i][j],f[i+Size[u]][j]);			
      		}
      	}
      	ans=max(ans,f[1][m]);
      }
      void solve(int t){
      	vis[t]=true;
      	calc();
      	for(int i=head[t];i;i=Next[i]){
      		int v=to[i];
      		if(vis[v]) continue;
      		rt=num=0;
      		sum=maxn[rt]=Size[v];
      		Get_zx(v,t);
      		dfs(rt,0);  
      		solve(rt);
      	}
      }
      
      void Init(){
      	tot=ans=0;
      	for(int i=1;i<=n;i++) head[i]=vis[i]=0;
      }
      signed main(){
      	int T=read();
      	while(T--){
      		n=read(),m=read();
      		Init();
      		
      		for(int i=1;i<=n;i++) w[i]=read();	
      		for(int i=1;i<=n;i++) c[i]=read();	
      		for(int i=1;i<=n;i++) d[i]=read();	
      		for(int i=1;i<n;i++){
      			int u=read(),v=read();
      			add(u,v),add(v,u);
      		}
      		
      		rt=num=0;
      		sum=maxn[rt]=n;
      		Get_zx(1,0);
      		dfs(rt,0);  
      		solve(rt); 
      		
      		printf("%lld\n",ans);
      	}
      	return 0;
      }
      
      posted @ 2024-12-30 16:37  Green&White  閱讀(93)  評論(0)    收藏  舉報
      主站蜘蛛池模板: 亚洲一区二区三区小蜜桃| 亚洲午夜成人精品电影在线观看| 妓院一钑片免看黄大片| 在线观看人成视频免费| 亚洲黄色成人网在线观看| 免费看婬乱a欧美大片| 欧美福利在线| 亚洲综合久久国产一区二区 | 在厨房拨开内裤进入在线视频| 曝光无码有码视频专区| 岛国最新亚洲伦理成人| 午夜精品久久久久久99热| 国产在线精品中文字幕| 2020国产欧洲精品网站| 亚洲日韩av在线观看| 亚洲av成人三区国产精品| 熟女精品国产一区二区三区| 免费观看在线A级毛片| 国产一区二区在线影院| 日日碰狠狠添天天爽| 亚洲男人AV天堂午夜在| 网友偷拍视频一区二区三区| 久热这里只有精品12| 少妇人妻精品一区二区| 人妻熟女一二三区夜夜爱| 成人网站国产在线视频内射视频 | 国产精品美女一区二三区| 免费人成在线观看网站| 亚洲情A成黄在线观看动漫尤物| 蜜桃传媒av免费观看麻豆| 久久夜色撩人国产综合av| 在线国产你懂的| 东京热人妻丝袜无码AV一二三区观| 亚洲国产精品热久久一区| 无码精品一区二区免费AV| 日韩在线不卡免费视频一区| 国产中文字幕精品在线| 偷偷色噜狠狠狠狠的777米奇| 欧美片内射欧美美美妇| 亚洲欧洲日韩精品在线| 滨海县|