题意:
题解:
文科生误点进来我不负责!上一篇也是!
太弱了太弱了迟早要烷
观察不到性质,只会骗分。QAQ
我们可以很容易写出50分算法:设
d
p
[
i
]
dp[i]
dp[i]表示以i为根的子树且i为其中一个小组的起点时的最大值。
很显然我们可以在整棵子树中枚举点v,维护从v往上走到达的点、
W
m
a
x
W_{max}
Wmax和
W
m
i
n
W_{min}
Wmin、u所有子树的dp值的和。
然后就可以dp了。
50分代码(想看正解的直接往下拉):
#include<cstdio>
#include<vector>
#include<algorithm>
#define maxn 100005
#define maxm 5005
#define LL long long
using namespace std;
int n,w[maxn],deg[maxn],minx[maxn],maxx[maxn],fa[maxn];
LL dp[maxn],sumch[maxn];
struct node { int v; node *nxt; } edge[maxn],*head[maxn],*ncnt;
vector<int> ch[maxm];
void addedge(int u,int v)
{
ncnt++;
ncnt->v=v,ncnt->nxt=head[u];
head[u]=ncnt;
}
void solve1(int u)
{
minx[u]=maxx[u]=w[u],fa[u]=u;
for(node *p=head[u];p;p=p->nxt)
{
int v=p->v;
solve1(v);
for(int i=0,siz=ch[v].size();i<siz;i++) ch[u].push_back(ch[v][i]);
ch[u].push_back(v); sumch[u]+=dp[v];
}
for(int i=0,siz=ch[u].size();i<siz;i++)
{
int v=ch[u][i];
minx[v]=min(minx[v],w[u]),maxx[v]=max(maxx[v],w[u]);
sumch[v]+=sumch[u]-dp[fa[v]],fa[v]=u;
dp[u]=max(dp[u],sumch[v]+maxx[v]-minx[v]);
}
}
int main()
{
scanf("%d",&n); ncnt=&edge[0];
for(int i=1;i<=n;i++) scanf("%d",&w[i]);
for(int i=1;i<n;i++)
{
int u,v;
scanf("%d%d",&u,&v);
addedge(u,v); deg[u]++;
}
if(n<=5000) solve1(1);
printf("%lld\n",dp[1]);
}
然而我说了这是50%算法。
满分算法需要get到一个性质:每一条链的值应该是单调的。
感性认识:如果在a到b之间不单调,那么b后面那些数就没有贡献,完全可以把a和b断掉。
然而我觉得就算我发现了这个性质我也想不到下面的东西
于是我们可以令
f
[
u
]
[
0
/
1
]
f[u][0/1]
f[u][0/1]表示以u为根的子树,它为顶点的链不减/不增时的最大值。然后
d
p
[
u
]
=
max
{
f
[
u
]
[
0
]
,
f
[
u
]
[
1
]
}
dp[u]=\max\{f[u][0],f[u][1]\}
dp[u]=max{f[u][0],f[u][1]}即可。
至于如何求f?见代码啊QWQ
当
w
[
v
]
>
=
w
[
u
]
w[v]>=w[u]
w[v]>=w[u],那么就是这条链不减,
f
[
u
]
[
0
]
=
max
{
f
[
u
]
[
0
]
,
s
u
m
−
d
p
[
v
]
+
f
[
v
]
[
0
]
+
w
[
v
]
−
w
[
u
]
}
f[u][0]=\max\{f[u][0],sum-dp[v]+f[v][0]+w[v]-w[u]\}
f[u][0]=max{f[u][0],sum−dp[v]+f[v][0]+w[v]−w[u]}。不用算整条链的原因是中间的f值已经减去w[v]。可参考求数列通项的累加法
反之同理。
代码:
#include<cstdio>
#include<vector>
#include<algorithm>
#define maxn 100005
#define maxm 5005
#define LL long long
using namespace std;
int n,w[maxn],deg[maxn],minx[maxn],maxx[maxn],pos[maxn],fa[maxn],dep[maxn];
LL dp[maxn],f[maxn][2],sumch[maxn];
struct node { int v; node *nxt; } edge[maxn],*head[maxn],*ncnt;
vector<int> ch[maxm];
void addedge(int u,int v)
{
ncnt++;
ncnt->v=v,ncnt->nxt=head[u];
head[u]=ncnt;
}
void solve1(int u)
{
for(node *p=head[u];p;p=p->nxt)
{
int v=p->v; solve1(v);
sumch[u]+=dp[v];
}
f[u][0]=f[u][1]=sumch[u];
for(node *p=head[u];p;p=p->nxt)
{
int v=p->v;
if(w[v]>=w[u]) f[u][0]=max(f[v][0]+sumch[u]-dp[v]+w[v]-w[u],f[u][0]);
if(w[v]<=w[u]) f[u][1]=max(f[v][1]+sumch[u]-dp[v]+w[u]-w[v],f[u][1]);
}
dp[u]=max(f[u][0],f[u][1]);
}
int main()
{
scanf("%d",&n); ncnt=&edge[0];
for(int i=1;i<=n;i++) { scanf("%d",&w[i]); pos[i]=i; }
for(int i=1;i<n;i++)
{
int u,v;
scanf("%d%d",&u,&v);
addedge(u,v); deg[u]++,fa[v]=u;
}
solve1(1);
printf("%lld\n",dp[1]);
}