给你一棵树,你需要在树上选择恰好 m条点不相交的、长度至少为 k的路径,使得路径所覆盖的点权和尽可能大。求最大点权和。
数据保证有解。
这是一道综合的题目,考察凸优化、长链剖分、树形DP、以及关于数组空间的优化
首先引进凸优化
对于这题来说,我们可以感性地理解,选的链的个数越多我们每次的增量就越小,也就是斜率递减,那么就成了一个凸函数。那么我们就可以用这个性质把m给省去。于是就变成求最大值了。
PS.所有的答案与点权都是整数,所以每次的增量也是整数,二分就不会存在精度问题。
我们显然可以运用树形DP,设f[x][i]表示以x为根的子树中,有一条以x为top的长度为i的链,符合题目的路径和这条链的总点权和。
总时间复杂度O(nlog(S)),空间复杂度O(n)。
S表示点权绝对值之和。
附上代码(第一次打,非常非常丑 )
#include
#include
#include
#include
#define maxn 150005
#define ll long long
using namespace std;
int n,m,K,i,j,k,x,y,Mxk;
ll v[maxn],l,r,mid,Mx;
ll f[maxn],f0[maxn],g[maxn],g0[maxn],tag[maxn],tag0[maxn];
int em,e[maxn*2],nx[maxn*2],ls[maxn];
int dep[maxn],pson[maxn],mxdep[maxn],tot,dfn[maxn],fa[maxn];
void insert(int x,int y){
em++; e[em]=y; nx[em]=ls[x]; ls[x]=em;
em++; e[em]=x; nx[em]=ls[y]; ls[y]=em;
}
void dfs(int x,int p){
dep[x]=dep[p]+1; pson[x]=0; mxdep[x]=dep[x];
for(int i=ls[x];i;i=nx[i]) if (e[i]!=p) {
dfs(e[i],x);
if (!pson[x]||mxdep[e[i]]>mxdep[x])
mxdep[x]=mxdep[e[i]],pson[x]=e[i];
}
}
void dfs2(int x,int p){
dfn[x]=++tot;
if (pson[x]) fa[pson[x]]=fa[x],dfs2(pson[x],x);
for(int i=ls[x];i;i=nx[i]) if (e[i]!=p&&e[i]!=pson[x])
fa[e[i]]=e[i],dfs2(e[i],x);
}
void dfs3(int x,int p,ll D){
ll s=0; int c=0; ll tmp; int tmpc;
for(int i=ls[x];i;i=nx[i]) if (e[i]!=p)
dfs3(e[i],x,D),s+=g[e[i]],c+=g0[e[i]];
g[x]=s,g0[x]=c;
tag[fa[x]]+=v[x]+s-g[pson[x]],tag0[fa[x]]+=c-g0[pson[x]];
f[dfn[x]]=v[x]+s-tag[fa[x]];
f0[dfn[x]]=c-tag0[fa[x]];
if (mxdep[x]>dep[x]&&(f[dfn[x]+1]>f[dfn[x]]||
f[dfn[x]+1]==f[dfn[x]]&&f0[dfn[x]+1]>f[dfn[x]]))
f[dfn[x]]=f[dfn[x]+1],f0[dfn[x]]=f0[dfn[x]+1];
if (mxdep[x]-dep[x]+1>=K){
tmp=f[dfn[x]+K-1]+tag[fa[x]]+D;
tmpc=f0[dfn[x]+K-1]+tag0[fa[x]]+1;
if (tmp>g[x]||tmp==g[x]&&tmpc>=g0[x])
g[x]=tmp,g0[x]=tmpc;
}
for(int i=ls[x];i;i=nx[i]) if (e[i]!=p&&e[i]!=pson[x]){
int y=e[i];
for(j=0;j<=mxdep[y]-dep[y];j++) if (K-j-1<=mxdep[x]-dep[x]+1) {
tmp=-g[y]+f[dfn[y]+j]+tag[fa[y]]+f[dfn[x]+max(1,K-j-1)-1]+tag[fa[x]]+D;
tmpc=-g0[y]+f0[dfn[y]+j]+f0[dfn[x]+max(1,K-j-1)-1]+tag0[fa[y]]+tag0[fa[x]]+1;
if (tmp>g[x]||tmp==g[x]&&tmpc>g0[x]) g[x]=tmp,g0[x]=tmpc;
}
for(j=mxdep[y]-dep[y];j>=0;j--) {
tmp=s-g[y]+f[dfn[y]+j]+tag[fa[y]]+v[x];
tmpc=c-g0[y]+f0[dfn[y]+j]+tag0[fa[y]];
if (tmp>f[dfn[x]+j+1]+tag[fa[x]]||
tmp==f[dfn[x]+j+1]+tag[fa[x]]&&tmpc>f0[dfn[x]+j+1]+tag0[fa[x]])
f[dfn[x]+j+1]=tmp-tag[fa[x]],f0[dfn[x]+j+1]=tmpc-tag0[fa[x]];
if ((f[dfn[x]+j]Mx) Mx=g[x],Mxk=g0[x];
}
int solve(ll D){
memset(f,0,sizeof(f));
memset(g,0,sizeof(g));
memset(f0,0,sizeof(f0));
memset(g0,0,sizeof(g0));
memset(tag,0,sizeof(tag));
memset(tag0,0,sizeof(tag0));
Mx=0,Mxk=0;
dfs3(1,0,D);
return Mxk;
}
int main(){
freopen("tree.in","r",stdin);
freopen("tree.out","w",stdout);
scanf("%d%d%d",&n,&m,&K);
ll s=0;
for(i=1;i<=n;i++) scanf("%lld",&v[i]),s+=abs(v[i]);
for(i=1;im) l=-s,r=0; else
if (km) r=mid; else
if (k