SHOI2015 聚变反应炉 题解

SHOI2015 聚变反应炉 题解

神秘数据分治题。

\(c\le 1\) 的点,发现先遍历 \(c=1\) 再遍历 \(c=0\) 的收益最高,贪心做即可。

\(n\le 2000\) 的点,发现 \(c\le 5\) 很有性质的样子,但是瞪不出来。发现可能是一个 \(O(n^2)\) 的 dp,设\(dp_{i,0/1}\) 为这个点先被激活/它的父亲先被激活的子树里的最小的代价。

然而这个不是很好转移,对于它的儿子与这个节点的激活顺序是对 dp 值是没有影响的,因为 \(c\le 5\) ,考虑一个背包,\(f_i\) 表示这个点被贡献了 \(i\) 次,最小的代价。这个直接由儿子的 dp 转移而来即可。接着 dp 就可以通过 \(f_i\) 来转移,注意有可能会被减到负数,这时需要判断一下。

code:

#include <bits/stdc++.h>
using namespace std;
const int N = 1E5 + 5;
int n, m, d[N], c[N];
int mx = 0;
vector<int> e[N];
int ans;
int dp[2005][2];
int tmp[2][10005],sum;

using namespace std;
namespace ly
{
    namespace IO
    {
        #ifndef LOCAL
            constexpr auto maxn=1<<20;
            char in[maxn],out[maxn],*p1=in,*p2=in,*p3=out;
            #define getchar() (p1==p2&&(p2=(p1=in)+fread(in,1,maxn,stdin),p1==p2)?EOF:*p1++)
            #define flush() (fwrite(out,1,p3-out,stdout))
            #define putchar(x) (p3==out+maxn&&(flush(),p3=out),*p3++=(x))
            class Flush{public:~Flush(){flush();}}_;
        #endif
        namespace usr
        {
            template<typename type>
            inline type read(type &x)
            {
                x=0;bool flag(0);char ch=getchar();
                while(!isdigit(ch)) flag^=ch=='-',ch=getchar();
                while(isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
                return flag?x=-x:x;
            }
            template<typename type>
            inline void write(type x)
            {
                x<0?x=-x,putchar('-'):0;
                static short Stack[50],top(0);
                do Stack[++top]=x%10,x/=10;while(x);
                while(top) putchar(Stack[top--]|48);
            }
            inline char read(char &x){do x=getchar();while(isspace(x));return x;}
            inline char write(const char &x){return putchar(x);}
            inline void read(char *x){static char ch;read(ch);do *(x++)=ch;while(!isspace(ch=getchar())&&~ch);}
            template<typename type>inline void write(type *x){while(*x)putchar(*(x++));}
            inline void read(string &x){static char ch;read(ch),x.clear();do x+=ch;while(!isspace(ch=getchar())&&~ch);}
            inline void write(const string &x){for(int i=0,len=x.length();i<len;++i)putchar(x[i]);}
            template<typename type,typename...T>inline void read(type &x,T&...y){read(x),read(y...);}
            template<typename type,typename...T>
            inline void write(const type &x,const T&...y){write(x),putchar(' '),write(y...),sizeof...(y)^1?0:putchar('\n');}
            template<typename type>
            inline void put(const type &x,bool flag=1){write(x),flag?putchar('\n'):putchar(' ');}
        }
        #ifndef LOCAL
            #undef getchar
            #undef flush
            #undef putchar
        #endif
    }using namespace IO::usr;
}using namespace ly::IO::usr;
inline void tomin(int &x,int y){
	if(x>y)x=y;
}
void dfs(int u,int fa) {
	int sum=0;
	for(int v:e[u]) {
		if(v==fa)continue;
		sum+=c[v];
		dfs(v,u);
	}
	for(int i=0;i<=sum;i++)tmp[0][i]=1e9;
	tmp[0][0]=0;
	int now=0;
	for(int v:e[u]) {
		if(v==fa)continue;
		now^=1;
		memset(tmp[now],0x3f,sizeof tmp[now]);
		for(int i=0; i<=sum-c[v]; i++) {
			tomin(tmp[now][i],tmp[now^1][i]+dp[v][1]);
			tomin(tmp[now][i+c[v]],tmp[now^1][i]+dp[v][0]);
		}
	}
	memset(dp[u],0x3f,sizeof dp[u]);
	for(int i=0; i<=sum; i++) {
		tomin(dp[u][0],max(tmp[now][i],tmp[now][i]-i+d[u]));
		tomin(dp[u][1],max(tmp[now][i],tmp[now][i]-i+d[u]-c[fa]));
	}
}
int main() {
	read(n);
	int t=0;
	for (int i = 1; i <= n; i++) read(d[i]),sum+=d[i];
	for (int i = 1; i <= n; i++) read(c[i]), mx = max(c[i], mx),t+=c[i];
	if(t==mx*n){
		put(sum-(n-1)*mx);
		return 0;
	}
	for(int i=1,u,v; i<n; i++) {
		read(u),read(v);
		e[u].push_back(v);
		e[v].push_back(u);
	}
	if(mx<=1) {
		for(int i=1; i<=n; i++)
			if(c[i]==1) {
				ans+=d[i];
				d[i]=0;
				for(int j:e[i])
					d[j]--;
			}
		for(int i=1; i<=n; i++)
			if(d[i]>0)ans+=d[i];
		put(ans);
		return 0;
	}
	dfs(1,0);put(dp[1][0]);
	return 0;
}
posted @ 2025-08-26 11:03  hnczy  阅读(14)  评论(0)    收藏  举报