题目大意
给一颗n个点的以1为根树,点权i值为a[i]。
定义相邻的叶子(x,y):x,y都是叶子节点(无儿子),而且在dfs序中,x,y之间没有其他叶子节点。
定义一棵树的贡献:所有叶子节点的权值减去所有相邻叶子的特殊贡献。
(x,y)的特殊贡献定义为,x到y路径上,除了x,y之外所有点的权值的最大值。
定义剪枝:如果一个点z的儿子都是叶子,剪枝可以把z的所有儿子去掉。
不限制剪枝次数,求树的最大贡献。
n<=105,答案保证不超过109
n
<=
10
5
,
答
案
保
证
不
超
过
10
9
分析
题意十分长,原题面更是掺杂了其他东西,审题要小心。
每次剪枝相当于把原来的叶子浓缩成他们的父亲,那么考虑到剪枝的特点,可以发现,对于原来的每个叶子x,1到x的路径必须要有一个点要被保留为叶子。
我们考虑使用DP,当然你也可以先尝试树形DP然后发现他的可行性。
设f[i]表示考虑了dfn为1~i的节点,此时这颗树(有可能未完成)的贡献。考虑转移,我们顺着DFS序,考虑从一个叶子到另外一个叶子的路径上所有点的转移/被转移。
(盗图,懒得做了)
可以看出是lca为分割点的两部分,左边的部分是被转移的点,右边是要转移到的点,lca及以上是不涉及转移的。我们暴力枚举两边的点进行转移,f[new]=max{f[old]-cost}+a[new],cost即为路径上权值最大值。这样就是
O(n2)
O
(
n
2
)
的了。
考虑优化,我们设h[old]表示从father[old],即old的父亲,到lca的路径的最大权值,H[new]表示从father[new]到lca路径的最大权值,那么原式变成f[new]=max{f[old]-max(h[old],H[new])}。注意到h和H的单调性,对于一个点new,把所有old点分为h[old]<=H[new]和h[old]>H[new]两部分,那么两部分的点都是连续的,就可以分开维护来更新f[new]了。
代码
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<set>
using namespace std;
typedef long long ll;
typedef double db;
#define fo(i,j,k) for(i=j;i<=k;i++)
#define fd(i,j,k) for(i=j;i>=k;i--)
const int N=2e5+5,mo=1e9+7,mx=1e9;
int dis[N],fa[N],b[N],nxt[N],fst[N],tt,a[N],d[N],e[N],f[N],g[N],h[N],w[N],mxf,H,r,i,j,x,y,n,ans;
void cr(int x,int y)
{
tt++;
b[tt]=y;
nxt[tt]=fst[x];
fst[x]=tt;
}
void dfs(int x)
{
//dfn[x]=++td;
dis[x]=dis[fa[x]]+1;
if (!fst[x])
d[++d[0]]=x;
for(int p=fst[x];p;p=nxt[p])
dfs(b[p]);
}
int main()
{
freopen("t3.in","r",stdin);
// freopen("t3.out","w",stdout);
scanf("%d\n",&n);
fo(i,1,n)
{
scanf("%d %d",a+i,&x);
fo(j,1,x)
{
scanf("%d",&y);
cr(i,y);
fa[y]=i;
}
}
dfs(1);
x=d[1];
while (x) f[x]=a[x],x=fa[x];
fo(i,1,d[0]-1)
{
w[0]=e[0]=0;
x=d[i];y=d[i+1];
while (dis[x]>dis[y]) e[++e[0]]=x,x=fa[x];
while (dis[x]<dis[y]) w[++w[0]]=y,y=fa[y];
while (x!=y)
{
e[++e[0]]=x,x=fa[x];
w[++w[0]]=y,y=fa[y];
}
fo(j,1,w[0]/2) swap(w[j],w[w[0]-j+1]);
fo(j,1,e[0]+1) h[j]=0;
fd(j,e[0],1) h[j]=max(h[j+1],a[fa[e[j]]]);
H=mxf=g[0]=-mx;
fo(j,1,e[0]) g[j]=max(g[j-1],f[e[j]]-h[j]);
r=e[0];
fo(j,1,w[0])
{
H=max(H,a[fa[w[j]]]);
while (r&&H>h[r])
{
mxf=max(mxf,f[e[r]]);
r--;
}
f[w[j]]=max(mxf-H,g[r])+a[w[j]];
}
}
x=d[d[0]];
while(x) ans=max(f[x],ans),x=fa[x];
printf("%d\n",ans);
}