[JZOJ5336] 提米树

来源:互联网 发布:网络小精灵国语版58网 编辑:程序博客网 时间:2024/06/07 00:38

题目大意

给一颗n个点的以1为根树,点权i值为a[i]。
定义相邻的叶子(x,y):x,y都是叶子节点(无儿子),而且在dfs序中,x,y之间没有其他叶子节点。
定义一棵树的贡献:所有叶子节点的权值减去所有相邻叶子的特殊贡献。
(x,y)的特殊贡献定义为,x到y路径上,除了x,y之外所有点的权值的最大值。
定义剪枝:如果一个点z的儿子都是叶子,剪枝可以把z的所有儿子去掉。
不限制剪枝次数,求树的最大贡献。
n<=105109

分析

题意十分长,原题面更是掺杂了其他东西,审题要小心。
每次剪枝相当于把原来的叶子浓缩成他们的父亲,那么考虑到剪枝的特点,可以发现,对于原来的每个叶子x,1到x的路径必须要有一个点要被保留为叶子。
我们考虑使用DP,当然你也可以先尝试树形DP然后发现他的可行性。
设f[i]表示考虑了dfn为1~i的节点,此时这颗树(有可能未完成)的贡献。考虑转移,我们顺着DFS序,考虑从一个叶子到另外一个叶子的路径上所有点的转移/被转移。
这里写图片描述
(盗图,懒得做了)
可以看出是lca为分割点的两部分,左边的部分是被转移的点,右边是要转移到的点,lca及以上是不涉及转移的。我们暴力枚举两边的点进行转移,f[new]=max{f[old]-cost}+a[new],cost即为路径上权值最大值。这样就是O(n2)的了。
考虑优化,我们设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);}