(翻译来自洛谷,侵权必删)
记
表示遍历
的子树所需要的总时间,
表示遍历
的子树且
的子树都装好了农场物语
所需要的时间。
我们发现 这么多的时间我们的管理员是浪费了的(如果他一直等着的话),所以为了节约时间,我们必然要对它加以利用。
所以,我们按 从大到小的顺序遍历求解即可。当然按 从大到小排序相当于按 从小到大排序。
//g即思路中的size,profit表示一个点装好电脑的时间
int f[N],ans,n,profit[N],g[N];
vector<pair<int,int> >G[N];
void dfs(int u,int fa){
if (u!=1) f[u]=profit[u];
for(int i=h[u];i;i=e[i].next)
if (e[i].to!=fa) dfs(e[i].to,u);
for(int i=h[u];i;i=e[i].next){
register int to=e[i].to;
if (to==fa) continue;
G[u].push_back(make_pair(g[to]-f[to],to));
}
sort(G[u].begin(),G[u].end());
for(int i=0;i<(int)G[u].size();i++){
register int to=G[u][i].second;
f[u]=max(f[u],f[to]+g[u]+1);
g[u]+=g[to]+2;//注意还有回来
}
}
int main(){
n=read();f[1]=ans=-1;
for(int i=1;i<=n;i++)
profit[i]=read();
for(int i=1;i<n;i++)
add(read(),read());
dfs(1,-1);ans=f[1];//注意因为管理员最后才给自己安装,所以根特殊计算
ans=max(ans,g[1]+profit[1]);
printf("%d",ans);
return 0;
}
************************
状态:Accepted
分数:100分
语言:c++
************************
本题看似排序了很多次,时间复杂度可能达到了 。其实不然,因为所有点的儿子数总和才是 ,所以时间复杂度最多为 。
某售货员小T
要到若干城镇去推销商品,由于该地区是交通不便的山区,任意两个城镇之间都只有
可能经过其它城镇的路线。 小T
可以准确地估计出在每个城镇停留的净收益。这些净收益可能是负数,即推销商品的利润抵不上花费。由于交通不便,小T
经过每个城镇都需要停留,在每个城镇的停留次数与在该地的净收益无关,因为很多费用不是计次收取的,而每个城镇对小T
的商品需求也是相对固定的,
。每个城镇为了强化治安,对外地人的最多停留次数有严格的规定。请你帮小T
设计一个收益最大的巡回方案,即从家乡出发,在经过的每个城镇停留,最后回到家乡的旅行方案。你的程序只需输出最大收益,以及最优方案是否唯一。方案并不包括路线的细节,方案相同的标准是选择经过并停留的城镇是否相同。因为取消巡回也是一种方案,因此最大收益不会是负数。小T
在家乡净收益是零,因为在家乡是本地人,家乡对小T
当然没有停留次数的限制。
记 表示从 出发遍历 的子树最后返回 所能获得的最大收益。因为次数有限制,所以理所当然地是按 从大到小遍历子树,直到用尽限制的次数为止(当然,如果收益为正的子树个数小于限制可走次数,那就宁可浪费啦)。
需要注意的是,不走的方案我们最后才考虑。而且记 表示可以访问 的次数的限制,则只能遍历 棵子树,因为从根到 也用了一次限制。
**************************************************************
Problem: 4472
Language: C++
Result: 正确
Time:404 ms
Memory:7172 kb
****************************************************************
const int N=1e5+100;
typedef long long ll;
int limit[N],profit[N],n;
ll dp[N];vector<ll> v[N];
struct node{
int next,to;
}e[N<<1];int h[N],tot;
inline void add(int a,int b){
e[++tot]=(node){h[a],b};h[a]=tot;
e[++tot]=(node){h[b],a};h[b]=tot;
}
inline bool cmp(ll a,ll b){
return a>b;
}
bool flag=true;//flag:方案是否唯一
void calc_answer(int u,int fa){
dp[u]=profit[u];int i;
for(i=h[u];i;i=e[i].next){
register int to=e[i].to;
if (to==fa) continue;
calc_answer(to,u);
v[u].push_back(dp[to]);
}
int t=min(limit[u]-1,(int)v[u].size());
sort(v[u].begin(),v[u].end(),cmp);
for(register int i=0;i<t;i++){
dp[u]+=max(v[u][i],0ll);
if (v[u][i]==0ll) flag=false;
}
if (t<(int)v[u].size()&&v[u][t+1]==v[u][t]) flag=false;
}
int main(){
// freopen("t1.in","r",stdin);
n=read();limit[1]=n+1;
for(int i=2;i<=n;i++)
profit[i]=read();
for(int i=2;i<=n;i++)
limit[i]=read();
for(int i=2;i<=n;i++)
add(read(),read());
calc_answer(1,-1);
printf("%lld\n",max(0ll,dp[1]));
if (dp[1]<=0ll) printf("solution is unique");
else if (flag) printf("solution is unique");
else printf("solution is not unique");
return 0;
}