首页 > 代码库 > hdu5293 Tree chain problem 树形dp+线段树

hdu5293 Tree chain problem 树形dp+线段树

题目:http://acm.hdu.edu.cn/showproblem.php?pid=5293

在一棵树中,给出若干条链和链的权值。求选取不相交的链使得权值和最大。


比赛的时候以为是树链剖分就果断没去想,事实上是没思路。

看了题解,原来是树形dp。话说多校第一场树形dp还真多。

。。


维护d[i],表示以i为根节点的子树的最优答案。

sum[i]表示i的儿子节点(仅仅能是儿子节点)的d值和。

那么答案就是d[root]。


怎样更新d值

d[i] = max(sum[i] , w[p]+sigma sum[j] - sigma d[j] );   p为以i为lca的链 。j为链上的点(注意:不须要减去d[i])

也就是。对于i,

要么是不选i,答案即sum[i]。他的儿子和。

要么是选i,即找一条过i的链,链的权值 + 这棵子树上不在链上的距离链近期的点的d值和。


维护链上的的sum和,d和 用线段树。

先通过树的遍历序将树上的节点链话。然后区间改动,单点查询。(每一个点的信息是改点到根节点路径上的和)


代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<vector>
#include<algorithm>
#include<cmath>
#pragma comment(linker, "/STACK:1024000000,1024000000")
using namespace std;
const int N = 100000+10;
typedef long long ll;
const int maxh = 25;
int st[N],ed[N],clock;


// ************************************
#define Lson Ls,L,mid
#define Rson Rs,mid+1,R

const int maxn = 100000+10;
const int inf = 100000000;
struct Node{
    ll val, set;
    ll val2 , set2;
}tree[N<<2];
inline void update(Node& fa, Node& Ls, Node& Rs){
    fa.val = Ls.val + Rs.val;
    fa.val2 = Ls.val2 + Rs.val2;
}
inline void pushdown(Node& fa, Node& Ls, Node& Rs){
    if (fa.set != 0){
        Ls.val += fa.set; Ls.set += fa.set;
        Rs.val += fa.set; Rs.set += fa.set;
        fa.set = 0;
    }
    if (fa.set2 != 0){
        Ls.val2 += fa.set2; Ls.set2 += fa.set2;
        Rs.val2 += fa.set2; Rs.set2 += fa.set2;
        fa.set2 = 0;
    }

}
void insert(int v, int L, int R, int p, int q, ll delta,ll delta2){
    if(p<=st[2]&& q>=st[2]&& delta2) {
    }
    if (p<=L && R<=q){
        tree[v].val += delta;
        tree[v].set += delta;

        tree[v].val2 += delta2;
        tree[v].set2 += delta2;
        return;
    }
    int Ls = v<<1, Rs = Ls+1, mid = (L+R)/2;
    pushdown(tree[v], tree[Ls], tree[Rs]);
    if (q<=mid) insert(Lson, p, q, delta,delta2);
    else if (p>mid) insert(Rson, p, q, delta,delta2);
    else{
        insert(Lson, p, q, delta,delta2);
        insert(Rson, p, q, delta,delta2);
    }
//    update(tree[v], tree[Ls], tree[Rs]);
}
ll query(int v, int L, int R,int ql, int qr){
    if(ql<=L && R<=qr){
        return tree[v].val;
    }
    int Ls = v<<1, Rs = Ls+1, mid = (L+R)/2;
    pushdown(tree[v], tree[Ls], tree[Rs]);
    ll ans = 0;
    if(qr<=mid) ans = query(Lson,ql,qr);
    else if(ql>mid) ans = query(Rson,ql,qr);
    else{
        ans = query(Lson,ql,qr) + query(Rson,ql,qr);
    }
//    update(tree[v], tree[Ls], tree[Rs]);
    return ans ;
}
ll query2(int v, int L, int R,int ql, int qr){
    if(ql<=L && R<=qr){
        return tree[v].val2;
    }
    int Ls = v<<1, Rs = Ls+1, mid = (L+R)/2;
    pushdown(tree[v], tree[Ls], tree[Rs]);
    ll ans = 0;
    if(qr<=mid) ans = query2(Lson,ql,qr);
    else if(ql>mid) ans = query2(Rson,ql,qr);
    else{
        ans = query2(Lson,ql,qr) + query2(Rson,ql,qr);
    }
//    update(tree[v], tree[Ls], tree[Rs]);
    return ans ;
}

// ***************************************




ll d[N],sum[N];
vector<int> g[N];
vector<int> list[N];
struct pp{
    int u,v,w;
}p[N];
int n,m,dep[N];
int anc[N][maxh+1];

void dfs(int x,int pre){
    st[x] = ++clock;
    anc[x][0] = pre;
    for(int i=0;i<g[x].size();i++)if(g[x][i]!=pre){
        int u = g[x][i];
        dep[u] = dep[x] + 1;
        dfs(u,x);
    }
    ed[x] = clock;
}
void lca_init(){
    clock = 0;
    dep[1] = 1;
    dfs(1,-1);
    for(int i=1;i<=maxh-1;i++){
        for(int j=1;j<=n;j++)
            if(anc[j][i-1]<0) anc[j][i] = -1;
            else anc[j][i] = anc[anc[j][i-1]][i-1];
    }
}
int swim(int x,int H){
    for(int i=0;H;i++){
        if(H&1) x = anc[x][i];
        H >>= 1;
    }
    return x;
}
int lca(int u,int v){
    if(dep[u]>dep[v]) swap(u,v);
    int H = dep[v]-dep[u];
    v = swim(v,H);
    if(u==v) return u;
    for(int k=maxh-1;k>=0;k--)
        if(anc[u][k]!=anc[v][k]){
            u = anc[u][k];
            v = anc[v][k];
        }
    return anc[u][0];
}


ll find(int u,int v,int la){
    ll ans = 0;
    ll s1 = query2(1,1,n,st[u],st[u]);
    ll s2 = query2(1,1,n,st[v],st[v]);
    ans = s1 + s2;

    ll d1 = query(1,1,n,st[u],st[u]);
    ll d2 = query(1,1,n,st[v],st[v]);
    ans -= d1 + d2;

    return ans+sum[la];
}

ll dfs_tree(int x,int pre){
    if(d[x]!=-1) return d[x];
    ll res = 0;
    sum[x] = 0;
    for(int i=0;i<g[x].size();i++)if(g[x][i]!=pre){
        int u = g[x][i];
        sum[x] += dfs_tree(u,x);
    }
    d[x] = sum[x];

    for(int i=0;i<list[x].size();i++){
        int id = list[x][i];
        ll tmp = p[id].w ;
        ll tmp1 = find(p[id].u,p[id].v,x);
        tmp += tmp1;
        d[x] = max(d[x] , tmp);
    }

    // update

    insert(1,1,n,st[x],ed[x],d[x],sum[x]);
    return d[x];
}

void solve(){
    memset(d,-1,sizeof(d));
    memset(tree,0,sizeof(tree));
    lca_init();
    for(int i=1;i<=n;i++) list[i].clear();
    for(int i=1;i<=m;i++){
        int u = p[i].u , v = p[i].v;
        int la = lca(u,v);
        list[la].push_back(i);
    }
    dfs_tree(1,-1);
}


int main(){
    int T;
    cin >> T;
    while(T--){
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++) g[i].clear();
        for(int i=1;i<=n-1;i++){
            int u,v;
            scanf("%d%d",&u,&v);
            g[u].push_back(v);
            g[v].push_back(u);
        }
        for(int i=1;i<=m;i++){
            int u,v,w;
            scanf("%d%d%d",&p[i].u,&p[i].v,&p[i].w);
        }
        solve();
        printf("%I64d\n",d[1]);
    }
    return 0;
}


hdu5293 Tree chain problem 树形dp+线段树