【HDU5293】Tree chain problem | 树形dp、LCA、树剖

题目大意:

给出一棵树,这棵树上分布着m条链,每条链都有一个权值,询问在保证选的链互不相交的情况下,最大的权值是多少

题目思路:

en ..

卡了一晚上,卡到了lca,吐啦

首先将这m条链的lca求出来,把每条链的两个端点放到lca里面。

之后就可以进行树形dp了

令dp[i]表示,以i为根的子树选出不重复链的最大权值

那么对于一个根节点u,选择经过u的链,和不经过u的链两种选择:

如果不选择经过u的链:那么对于子树无限制,所以sum += dp[e] //e是u的孩子

如果选择经过u的链:

 假设有1条从1->3的链,那么选择了这条链的答案就是蓝色子树部分的最大值。

由此可以得出,如果这条链上存在u这个节点,那么u所有的子节点贡献应该被加入答案,但是如果v->u,并且u与v均在链上,这时要加上u的所有子节点 + v的所有子节点 - u的节点

所以综上,对于每个节点维护一个 :所有子节点dp的值和 - 当前节点dp值。那么经过u选择一条链的答案就是,u的所有子节点的和 + 链(x,y)上权值的和 + 该条链的权值

所以用树剖维护一下就可以了

附赠比较卡人的几个样例~

Code:

/*** keep hungry and calm CoolGuang!  ***/
#pragma GCC optimize("Ofast","unroll-loops","omit-frame-pointer","inline")
#pragma GCC optimize(3)
#include <bits/stdc++.h>
#include<stdio.h>
#include<queue>
#include<algorithm>
#include<string.h>
#include<iostream>
#define debug(x) cout<<#x<<":"<<x<<endl;
#define d(x) printf("%lld\n",x);
typedef long long ll;
typedef unsigned long long ull;
using namespace std;
const ll INF= 1e18;
const ll maxn = 4e5+700;
const int mod= 998244353;
const int up = 1e9;
template<typename T>inline void read(T &a){char c=getchar();T x=0,f=1;while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}
while(isdigit(c)){x=(x<<1)+(x<<3)+c-'0';c=getchar();}a=f*x;}
ll n,m,p;
vector<int>v[maxn];
struct node{
    int x,y,w;
};
vector<node>q[maxn];
int f[maxn][22],deep[maxn];
int son[maxn],sz[maxn],dfn = 0;
void dfs(int u,int fa){
    deep[u] = deep[fa] + 1;
    f[u][0] = fa;
    for(int i=1;i<=20;i++) f[u][i] = f[f[u][i-1]][i-1];
    sz[u] = 1;
    for(int e:v[u]){
        if(e == fa) continue;
        dfs(e,u);
        sz[u] += sz[e];
        if(sz[son[u]] < sz[e]) son[u] = e;
    }
}
int __LCA(int u,int v){
    if(deep[u]<deep[v]) swap(u,v);
    for(int i=20;i>=0;i--)   if(deep[f[u][i]]>=deep[v]) u=f[u][i];
    if(u==v) return u;
    for(int i=20;i>=0;i--){
        if(f[u][i]!=f[v][i]){
            u=f[u][i];
            v=f[v][i];
        }
    }
    return f[u][0];
}
///LCA
///树剖
ll sum[maxn];
int top[maxn],L[maxn];
void add(int pos,ll w){
    while(pos <= n){
        sum[pos] += w;
        pos += pos&-pos;
    }
}
ll GetSum(int pos){
    ll ans = 0;
    while(pos){
        ans += sum[pos];
        pos -= pos&-pos;
    }return ans;
}
void dfs1(int u,int fa,int t){
    L[u] = ++dfn;
    top[u] = t;
    if(!son[u]) return ;///leaf
    dfs1(son[u],u,t);
    for(int e:v[u]){
        if(e == fa || e == son[u]) continue;
        dfs1(e,u,e);
    }
}
///树形dp
ll dp[maxn];
ll QueryTree(int x,int y){///链x - > y
    ll ans = 0;
    while(top[x]!=top[y]){
        if(deep[top[x]]<deep[top[y]]) swap(x,y);
        ans = ans+GetSum(L[x])-GetSum(L[top[x]]-1);
        x=f[top[x]][0];
    }
    if(deep[x]>deep[y]) swap(x,y);
    ans = ans + GetSum(L[y])-GetSum(L[x]-1);
    return ans;
}
ll ans = 0;
void Tree_dp(int u,int fa){
    ll temp = 0;
    for(int e:v[u]){
        if(e == fa) continue;
        Tree_dp(e,u);
        temp += dp[e];
    }
    dp[u] = temp;
    for(node tt:q[u]){
        int x = tt.x,y = tt.y,w = tt.w;
        dp[u] = max(dp[u],temp+QueryTree(x,u)+QueryTree(y,u)+w);
    }
    add(L[u],temp-dp[u]);
}
int main(){
    int T;scanf("%d",&T);
    while(T--){
        read(n);read(m);
        dfn = 0;
        for(int i=1;i<=n;i++) v[i].clear(),q[i].clear(),son[i] = 0;
        for(int i=0;i<=n;i++) dp[i] = 0,sum[i] = 0;
        for(int i=1;i<=n-1;i++){
            int x,y;read(x);read(y);
            v[x].push_back(y);
            v[y].push_back(x);
        }
        deep[1] = 0;
        dfs(1,1);
        dfs1(1,1,1);
        for(int i=1;i<=m;i++){
            int x,y,w;read(x);read(y);read(w);
            int lca = __LCA(x,y);
            q[lca].push_back(node{x,y,w});
        }

       /* for(int i=1;i<=n;i++){
            for(node tt:q[i]){
                printf("%d:%d %d %d\n",i,tt.x,tt.y,tt.w);
            }
        }*/

        ans = 0;
        Tree_dp(1,1);
       /* for(int i=1;i<=n;i++)
            printf("%lld ",dp[i]);
        printf("\n");*/
        printf("%lld\n",dp[1]);
    }
    return 0;
}
/***
4
7 4
1 2
1 3
2 4
2 5
3 6
3 7
1 4 7
2 4 5
1 6 5
6 6 5


7 3
1 2
1 3
2 4
2 5
3 6
3 7
1 4 1
5 5 1
6 7 1

4 3
1 2
2 3
2 4
2 2 5
3 4 6
1 1 2

7 4
1 2
1 3
2 4
2 5
3 6
3 7
1 5 4
4 4 2
4 3 7
5 5 2
***/

猜你喜欢

转载自blog.csdn.net/qq_43857314/article/details/111102212