一本通1774:大逃杀

链接

(f_{i,j}) 表示在 (i) 子树中,起点终点都为 (i) ,时间为 (j) 的最大武装值,
同理 (g_{i,j}) 表示起点或终点为 (i)(h_{i,j}) 表示起点终点都在 (i) 的子树内。
通过枚举起点终点是否在孩子的子树中,可以得到 (dp) 式子。

#include<bits/stdc++.h>
#define IL inline
#define LL long long
using namespace std;
const int N=3e2+3;
struct hh{
	int to,nxt,w;
	}e[N<<1];
int n,T,num,fir[N],w[N],t[N],f[N][N],g[N][N],h[N][N],ans;
IL int in(){
	char c;int f=1;
	while((c=getchar())<'0'||c>'9')
		if(c=='-') f=-1;
	int x=c-'0';
	while((c=getchar())>='0'&&c<='9')
		x=x*10+c-'0';
	return x*f;
	}
IL void add(int x,int y,int z){e[++num]=(hh){y,fir[x],z},fir[x]=num;}
IL void chk(int &x,int y){if(x<y) x=y;}
void dfs(int u,int fa){
	if(t[u]<=T) f[u][t[u]]=g[u][t[u]]=h[u][t[u]]=w[u];
	for(int k=fir[u],v;v=e[k].to;k=e[k].nxt)
		if(v^fa){
			dfs(v,u);
			for(int i=T;i>=t[u];--i){
				for(int j=i-e[k].w;j>=t[u];--j){
					int ff=f[u][j],gg=g[u][j],hh=h[u][j];
					int t1=i-j-2*e[k].w,t2=i-j-e[k].w;
					if(t1>=t[v]) chk(f[u][i],ff+f[v][t1]);
					if(t1>=t[v]) chk(g[u][i],gg+f[v][t1]);
					if(t2>=t[v]) chk(g[u][i],ff+g[v][t2]);
					if(t1>=t[v]) chk(h[u][i],hh+f[v][t1]);
					if(t2>=t[v]) chk(h[u][i],gg+g[v][t2]);
					if(t1>=t[v]) chk(h[u][i],ff+h[v][t1]);
					}
				chk(ans,h[u][i]);
				}
			}
	}
int main()
{
	int x,y,z;
	n=in(),T=in();
	for(int i=1;i<=n;++i) w[i]=in();
	for(int i=1;i<=n;++i) t[i]=in();
	for(int i=1;i<n;++i)
		x=in(),y=in(),z=in(),
		add(x,y,z),add(y,x,z);
	dfs(1,0);
	printf("%d
",ans);
	return 0;
	}
原文地址:https://www.cnblogs.com/yiqiAtiya/p/13926604.html