聚变反应炉
读完题过后,我们发现n大的数据c只有0或者1的情况,很显然是要我们分类讨论,(如果不分类只有80分,会T)
我们换一个角度来看这道题的答案
他让我们求出按顺序点亮一些点,然后总共的花费是多少
我们可以视作我们已经点了所有点,然后按顺序点一些点,最后最多能减少多少的花费
case 1:(c只有0或者1)
很显然是把1的点优先点亮,然后再点0的点
模拟一下即可
for(i=1;i<=n;++i)
if(c[i]){ //如果是1
ans=ans+d[i]; //加上花费
d[i]=0; //花费搞成0
for(j=head[i];!!j;j=nex[j])
--d[to[j]]; //相邻的点-1
}
for(i=1;i<=n;++i)
if(d[i]>0)ans=ans+d[i];//点亮为0的点
printf("%d\n",ans);
case 2:
我们假设要求x
那么我们可以有两种情况
1.我们先点亮fa[x]再点亮x
2.我们先点亮x再点亮fa[x]
那么我们就设f[x][0/1] 表示情况2/1
那么我们考虑如何求出f[x][0/1]
我们在设tmp[i] 表示x收到了来自儿子的i能量,把子树搞好的最小价值
就可以轻松求出f[x][0/1]
那么现在的问题是求出tmp[i]
很显然我们可以用滚动数组+背包求出来
\(tmp[now][i]=min(f[y][0]+tmp[now \space xor \space 1][i-c[y]],f[y][1]+tmp[now \space xor \space 1][i])\)
然后就完了
inline void dfs(int x,int ne){
int i,sum(0),y;
for(i=head[x];!!i;i=nex[i]){
y=to[i];
if(y==ne)continue;
dfs(y,x);
sum=sum+c[y];
}
int now(0),j;
memset(tmp[now],63,sizeof(tmp[now]));
tmp[now][0]=0;
for(i=head[x];!!i;i=nex[i]){
y=to[i];
if(y==ne)continue;
now^=1;
memset(tmp[now],63,sizeof(tmp[now]));
for(j=sum;j>=0;--j){
if(j+c[y]<=sum)tmp[now][j+c[y]]=min(tmp[now][j+c[y]],tmp[now^1][j]+f[y][0]);
tmp[now][j]=min(tmp[now][j],tmp[now^1][j]+f[y][1]);
}
}
memset(f[x],63,sizeof(f[x]));
for(i=0;i<=sum;++i)
f[x][0]=min(f[x][0],max(tmp[now][i],tmp[now][i]+d[x]-i)),
f[x][1]=min(f[x][1],max(tmp[now][i],tmp[now][i]+d[x]-i-c[ne]));
}
代码
#include<bits/stdc++.h>
#define N 100011
#define M 200011
#define MAXSUM 501011
using namespace std;
int head[N],nex[M],to[M],tot;
inline void build(int x,int y){
to[++tot]=y;
nex[tot]=head[x];
head[x]=tot;
}
int d[N],c[N];
int tmp[2][MAXSUM],n,f[N][2];
inline void dfs(int x,int ne){
int i,sum(0),y;
for(i=head[x];!!i;i=nex[i]){
y=to[i];
if(y==ne)continue;
dfs(y,x);
sum=sum+c[y];
}
int now(0),j;
memset(tmp[now],63,sizeof(tmp[now]));
tmp[now][0]=0;
for(i=head[x];!!i;i=nex[i]){
y=to[i];
if(y==ne)continue;
now^=1;
memset(tmp[now],63,sizeof(tmp[now]));
for(j=sum;j>=0;--j){
if(j+c[y]<=sum)tmp[now][j+c[y]]=min(tmp[now][j+c[y]],tmp[now^1][j]+f[y][0]);
tmp[now][j]=min(tmp[now][j],tmp[now^1][j]+f[y][1]);
}
}
memset(f[x],63,sizeof(f[x]));
for(i=0;i<=sum;++i)
f[x][0]=min(f[x][0],max(tmp[now][i],tmp[now][i]+d[x]-i)),
f[x][1]=min(f[x][1],max(tmp[now][i],tmp[now][i]+d[x]-i-c[ne]));
}
int main( ){
scanf("%d",&n);
int i,j,k;
int x,y,z,maxc(0);
for(i=1;i<=n;++i)
scanf("%d",&d[i]);
for(i=1;i<=n;++i){
scanf("%d",&c[i]);
maxc=max(maxc,c[i]);
}
for(i=1;i<n;++i){
scanf("%d%d",&x,&y);
build(x,y);
build(y,x);
}
int ans(0);
if(maxc<=1){
for(i=1;i<=n;++i)
if(c[i]){
ans=ans+d[i];
d[i]=0;
for(j=head[i];!!j;j=nex[j])
--d[to[j]];
}
for(i=1;i<=n;++i)
if(d[i]>0)ans=ans+d[i];
printf("%d\n",ans);
return 0;
}
dfs(1,0);
printf("%d\n",f[1][0]);
}