说在前面
这个水题写了我一个白天= =
就因为建边忘了建双向边,以为所有给的边都是father->son的
简直*了狗(狗:woc关我啥事)
题目
题目大意
给你一棵含有n个节点的树,每个节点有权值(可正可负),并且每个节点有路过次数上限。仅在第一次路过某个节点后,获得该节点的权值。现问从1号节点出发,在树上随便跑(可以不进入某些节点)后能获得的最大收益,并输出方案是否唯一。
若唯一,输出solution is unique
else,输出solution is not unique
方案唯一是指:至少有两个方案可以达到该权值,并且此两方案路过的节点不至少有一个点不同。
输入
第一行一个整数:n,代表总节点数。
第二行n-1个整数,代表第二到第n个点的权值
第三行n-1个整数,代表第二到第n各节点最大可路过次数
接下来n-1行,每行两个整数,代表此两节点之间有一条边。
9
-3 -4 2 4 -2 3 4 6
4 4 2 2 2 2 2 2
1 2
1 3
1 4
2 5
2 6
3 7
4 8
4 9
数据保证每个节点路过次数不小于二,并且从1可以到达任意一点,即整个图是联通的,不是森林。1号节点进入次数不限,权值为0.
输出
9
solution is unique
解法
一开始看到这个题可能会想到树形背包
然而这道题因为不确定选点的个数,因此背包的容积是不确定的,因此不能用背包做。
看到这里,请读者仔细思考一下该题正解:
·
·
·
·
·
·
·
·
·
·
·
如果还没想出来–>请回头看一下本文标题
.
.
.
.
.
.
.
.
.
.
.
可以发现,节点的权值有正有负,由于我们路过点的次数有限,那么我们肯定是尽量的把正权值的点选完
于是思路出来了:
递归处理每个子节点,然后把已经处理好的子节点的最优解从大到小排序,如果正权值已经选完,或者选的节点到达上限,就退出循环。
那么如何确定解是不是唯一呢?
在把子树的最大收益计算出来之后,是排了一遍 续....续1s!序的。如果当前选择的最后一个节点,和第一个me没选的节点收益一样,那么方案不唯一。如果me选中的节点中有收益为0的,那么方案也不唯一。
下面是自带大常数的代码:
其中,pro[i]代表的是点i的初始利润
dp数组为处理之后,路过改点获得的最大收益
isnotuni==is not unique
tim[i]表示i点最大可经过次数
其余的应该都能懂 ~
/* *************************************************************
Problem: 4472
User: Izumihanako
Language: C++
Result: Accepted
Time:336 ms
Memory:4340 kb
*************************************************************** */
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<vector>
using namespace std;
int n,pro[100001],tim[100001],head[100001],tw=0;
int dp[100001],isnotuni[100001];
struct node{
int pre,to;
}w[200001];
int comp(const pair<int,int > &a,const pair<int,int > &b){
if(a.first<b.first) return 0;
return 1;
}
void In(int t1,int t2){
w[++tw].pre=head[t1];
w[tw].to=t2;
head[t1]=tw;
}
void work(int u,int f){
vector< pair<int,int> > Ve;
Ve.clear();
for(int i=head[u];i;i=w[i].pre){
int v=w[i].to;
if(v==f) continue;
work(v,u);
Ve.push_back(make_pair<int,int>(dp[v],v));
}
sort( Ve.begin(), Ve.end(), comp);
int i=0,R=Ve.size()-1;
for(;i<=R&&i+2<=tim[u]&&Ve[i].first>=0;i++){
isnotuni[u]|=isnotuni[Ve[i].second];
dp[u]+=Ve[i].first;
}
if(i>0&&i!=Ve.size())
isnotuni[u]|=(Ve[i-1].first==Ve[i].first ? 1 : 0);
if(i>0&&Ve[i-1].first==0)
isnotuni[u]=1;
dp[u]+=pro[u];
}
inline int read()
{
int data=0,w=1; char ch=0;
while(ch!='-' && (ch<'0' || ch>'9')) ch=getchar();
if(ch=='-') w=-1,ch=getchar();
while(ch>='0' && ch<='9') data=data*10+ch-'0',ch=getchar();
return data*w;
}
int main(){
int t1,t2;
scanf("%d",&n);
for(int i=2;i<=n;i++)
pro[i]=read();
for(int i=2;i<=n;i++)
tim[i]=read();
tim[1]=0x3f3f3f3f;
for(int i=2;i<=n;i++){
t1=read();t2=read();
In(t1,t2);
In(t2,t1);
}
work(1,0);
printf("%d\n",dp[1]);
if(isnotuni[1]==1)
printf("solution is not unique");
else
printf("solution is unique");
return 0;
}