eom选择的时候:
dp[i]=make_pair(dp[j].eom+a[i],dp[j].moe)
j为节点i的儿子中dp[j].first尽可能大并在此基础上dp[j].second尽可能小的儿子编号。
moe选择的时候:
dp[i]=make_pair(dp[k].eom,dp[k].moe+a[i])
k为节点i的儿子中dp[k].first尽可能小并在此基础上dp[k].second尽可能大的儿子编号。
我们需要一个递归dfs的方式来构建出树形的结构,为此的前置准备有读入,前向星建单向图,并以结构体构建dp数组来保存状态。关键在于dfs的写法,
需要现在节点的位置now和选择的人who,在从now走图的返回结果中每一次都根据选择的方案更新选择的儿子节点,循环递归之后根据最优儿子节点更新当前节点的dp值。
(好像写起来并不难?)
#include<bits/stdc++.h>
#define FOR(a, b, c) for(int a=b; a<=c; a++)
#define maxn 2000005
#define maxm 55
#define hrdg 1000000007
#define inf 2147483647
#define llinf 9223372036854775807
#define ll long long
#define pi acos(-1.0)
#define ls p<<1
#define rs p<<1|1
using namespace std;
char s[4];
int n, u, v, type;
ll val[maxn];
struct Edge{int to, nex;}edge[maxn];
int head[maxn], tot;
struct node{
ll moe, eom;
}dp[maxn];
inline int read(){
char c=getchar();long long x=0,f=1;
while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
return x*f;
}
void add_edge(int u, int v){
tot++;
edge[tot].nex = head[u];
edge[tot].to = v;
head[u] = tot;
}
bool cmp2(int x, int y){ //moe想要的排序规则
if(x == 0) //就是说当前的best==0,那么可以直接赋值
return true;
if(dp[y].eom > dp[x].eom)
return true;
if(dp[x].eom == dp[y].eom)
if(dp[y].moe <= dp[x].moe)
return true;
return false;
}
bool cmp1(int x, int y){ //eom想要的排序规则,后来我发现他们都是以eom的石子数量为第一标准,这两个规则可以合并的其实
if(x == 0)
return true;
if(dp[y].eom < dp[x].eom)
return true;
if(dp[x].eom == dp[y].eom)
if(dp[y].moe >= dp[x].moe)
return true;
return false;
}
void dfs(int now, int who)
{
int best = 0;
for (int i = head[now]; i; i = edge[i].nex)
{
int to = edge[i].to;
dfs(to, !who);
if(who == 1 && cmp1(best, to)) //两个排序规则,本来可以处理的更聪明些的,但是也没差其实,至少思路还算清晰
best = to;
if(who == 0 && cmp2(best, to))
best = to;
}
if(who == 1) //有best的选择了,那么就看是谁拿的,赋值更新当前节点即可
{
dp[now].eom = dp[best].eom + val[now];
dp[now].moe = dp[best].moe;
}
else
{
dp[now].eom = dp[best].eom;
dp[now].moe = dp[best].moe + val[now];
}
}
int main()
{
scanf("%s", s);
if(!strcmp(s, "eom"))
type = 1;
else
type = 0;
//printf("type = %d\n", type);
n = read();
memset(dp, 0, sizeof(dp));
for (int i = 1; i <= n; i++)
val[i] = read(); //初始化和读入
for (int i = 1; i < n; i++)
{
u = read(); v = read();
add_edge(u, v); //前向星建图,有向边
}
dfs(1, type); //递归深搜
printf("%lld %lld", dp[1].eom, dp[1].moe); //打印结果
return 0;
}
/*
moe
6
1 3 5 3 4 2
1 2
1 3
3 4
3 5
5 6
*/