HDU5293 Tree chain problem - 树形dp&树状数组优化

来源:互联网 发布:显卡软件超频 编辑:程序博客网 时间:2024/06/04 18:05

题目描述

题目大意:

给定一棵有 n 个点的树,以及 m 条树链,其中第 i 条树链 的价值为 wi,请选择一些没有公共点的树链,使得价值和最大。
1 ≤n,m≤ 100000。
Source:2015 Multi-University Training Contest 1

分析:

  • 设f[u]为u为根的子树上选择没有公共点的树链所得的最大价值和。
  • 转移方程:
    枚举链的两端点的lca为u的链,记w为当前链的价值
    f[u]=max{f[u.son],w+kf[k]}
  • 时间复杂度O((n+m)*n),过不了,选择优化,记sum[u]为u的所有儿子v的f[v]之和,得到:

    f[u]=max{f[u.son],w+jsum[j]f[j]}

    (链上的点会在它的父亲的sum[]中多加,要再减去)

    可根据dfs序维护树状数组来实现优化。

#include<cstdio>#include<cstring>#include<algorithm>#include<vector>using namespace std;#define MAXN 100000#define MAXM 100000#define MAXLOG 20typedef long long LL;struct node{    int v;    node *next;}edge[MAXN*2+10],*adj[MAXN+10],*ecnt=&edge[0];vector<int> pnt[MAXN+10];int n,m,LogN,chain[MAXM+10][3];int fa[MAXN+10],dep[MAXN+10],P[MAXN+10][MAXLOG+10];int in[MAXN+10],out[MAXN+10],cntd;LL c[2*MAXN+10],f[MAXN+10];void Init(){    memset(adj,0,sizeof adj);    ecnt=&edge[0];    memset(pnt,0,sizeof pnt);    memset(fa,0,sizeof fa);    memset(dep,0,sizeof dep);    memset(f,0,sizeof f);    cntd=0;    memset(c,0,sizeof c);}void addedge(int u,int v){    node *p=++ecnt;    p->v=v;    p->next=adj[u];    adj[u]=p;}void dfs(int u,int prev,int L){    fa[u]=prev;    dep[u]=L;    for(node *p=adj[u];p;p=p->next){        if(p->v==fa[u]) continue;        dfs(p->v,u,L+1);    }}void LCA_pre(){    memset(P,-1,sizeof P);    for(int i=1;i<=n;i++)        P[i][0]=fa[i];    for(LogN=0;(1<<LogN)<=n;LogN++);    LogN--;    for(int j=1;j<=LogN;j++){        for(int i=1;i<=n;i++)            if(P[i][j-1]!=-1)                P[i][j]=P[P[i][j-1]][j-1];    }}int LCA(int x,int y){    if(dep[x]<dep[y])        swap(x,y);    int Logx;    for(Logx=0;(1<<Logx)<=dep[x];Logx++);    Logx--;    for(int i=Logx;i>=0;i--)        if(dep[P[x][i]]>=dep[y])            x=P[x][i];    if(x==y) return x;    for(int i=Logx;i>=0;i--)        if(P[x][i]!=P[y][i])            x=P[x][i],y=P[y][i];    return fa[x];}void read(){    int x,y;    scanf("%d%d",&n,&m);    for(int i=1;i<n;i++){        scanf("%d%d",&x,&y);        addedge(x,y);        addedge(y,x);    }    dfs(1,0,1);    LCA_pre();    for(int i=1;i<=m;i++){        scanf("%d%d%d",&chain[i][0],&chain[i][1],&chain[i][2]);        int lca=LCA(chain[i][0],chain[i][1]);        pnt[lca].push_back(i);    }}int lowbit(int x){    return x&(-x);}void Update(int x,LL d){    while(x<=2*n){        c[x]+=d;        x+=lowbit(x);    }}LL Getsum(int x){    LL ret=0;    while(x){        ret+=c[x];        x-=lowbit(x);    }    return ret;}void DP(int u) //dfs for dp on the tree{    LL g_u=0;    in[u]=++cntd;    for(node *p=adj[u];p;p=p->next){        if(p->v==fa[u]) continue;        DP(p->v);        g_u+=f[p->v];    }    out[u]=++cntd;    Update(in[u],g_u);    Update(out[u]+1,-g_u);    f[u]=g_u;    int side=pnt[u].size();    for(int i=0,num;i<side;i++){        num=pnt[u][i];        f[u]=max(f[u],Getsum(out[chain[num][0]])+Getsum(out[chain[num][1]])+1LL*chain[num][2]-g_u);    }    Update(in[u],-f[u]);    Update(out[u]+1,f[u]);}int main(){    int T;    scanf("%d",&T);    while(T--){        Init();        read();        DP(1);        printf("%I64d\n",f[1]);    }}
1 0
原创粉丝点击