【HDU5293】Tree chain problem | Tree dp, LCA, tree section

Main idea:

Given a tree with m chains distributed on this tree, each chain has a weight, and ask what the maximum weight is when the selected chains are not intersected

Question idea:

in ..

Stuck all night, got stuck in lca, vomit

First, find the lca of the m chains, and put the two end points of each chain into the lca.

Then you can perform tree dp

Let dp[i] denote the maximum weight of the non-duplicated chain selected by the subtree rooted at i

Then, for a root node u, there are two choices for the chain that passes u and the chain that does not pass u:

If you do not choose the chain that goes through u: then there is no restriction on the subtree, so sum += dp[e] //e is a child of u

If you choose a chain that goes through u:

 

 Suppose there is a chain from 1->3, then the answer to this chain is the maximum value of the blue subtree.

It can be concluded that if there is a node u on this chain, then all the child node contributions of u should be added to the answer, but if v->u, and both u and v are on the chain, then u must be added All children of v + all children of v-node of u

So in summary, maintain one for each node: the dp value of all child nodes and-the dp value of the current node. Then the answer to selecting a chain after u is, the sum of all the child nodes of u + the sum of weights on the chain (x, y) + the weight of the chain

So use the tree to maintain it.

A few examples of comparison card holders are included~

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
***/

 

Guess you like

Origin blog.csdn.net/qq_43857314/article/details/111102212