hdu5293(2015多校1)--Tree chain problem(树状dp)

Tree chain problem

Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)

Total Submission(s): 262    Accepted Submission(s): 59

Problem Description

Coco has a tree, whose vertices are conveniently labeled by 1,2,…,n.

There are m chain on the tree, Each chain has a certain weight. Coco would like to pick out some chains any two of which do not share common vertices.

Find out the maximum sum of the weight Coco can pick

Input

The input consists of several test cases. The first line of input gives the number of test cases T (T<=10).

For each tests:

First line two positive integers n, m.(1<=n,m<=100000)

The following (n - 1) lines contain 2 integers ai bi denoting an edge between vertices ai and bi (1≤ai,bi≤n),

Next m lines each three numbers u, v and val(1≤u,v≤n,0<val<1000), represent the two end points and the weight of a tree chain.

Output

For each tests:

A single integer, the maximum number of paths.

Sample Input

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

Sample Output

6

Hint

 Stack expansion program: #pragma comment(linker, "/STACK:1024000000,1024000000") 

题目大意:有一颗n个节点的数,给出n-1条边(无向),还有m条链,每条链链接两个顶点(按lca的方式链接),链存在一个权值w,现在想要挑选一些链,挑选的链中不能出现相同的节点,问可以挑选出的最大的权重是多少?

要求权值最大,按照树形dp的思路去考虑,那么dp[i]为以第i个点位根节点的子树的最优解。dp[i]的状态转移公式,有两种可能,第一种:第i个节点上不出现链,那么dp[i] = ∑(dp[k] | k为i的子节点);第二种:第i个节点上出现链,如果选择加入这条链,那么dp[i] = w(链的权值) + ∑(dp[k] | k为链上的节点的子节点) = w + ∑(sum[k]
| k为链上的节点 ) - ∑(dp[k] | k为链上的节点) 。sum[i]表示i节点的所有子节点的dp和,在 ∑(sum[k] | k为链上的节点 ) - ∑(dp[k] | k为链上的节点) 中减去的dp[k]会由它的父节点的sum补全。这样就得到了状态转移公式。

还有要计算给出的链的两个顶点的lca(用于更新dp的值),在更新dp值的时候需要计算链上节点的(sun的和)(dp的和),使用树状数组来计算,对所有节点进行dfs,对点进行重新编号,每到达一个点和每离开一个点都要编号,记录在l[i]和r[i]中,当计算玩一个sum[i]值后,加到树状数组c1中(l[i]位置加正值,r[i]位置加负值),计算完一个dp[i]值后,加到树状数组c2中(l[i]位置加正值,r[i]位置加负值),按照新的编号进行树状数组计算区间和,也就可以得到链上的节点的和

总结:

1、建树,题目给出的(无向边),要加双边

2、dfs,建立rmq[i][j]:i节点的第2^j个父节点,对节点重新编号

3、对给出的两个顶点求lca,(代码中用rmq求lca)

4、树状数组,求区间和。

5、深搜,完成树形dp,按状态转移方程计算每一个节点的值,使用树状数组计算链上节点的和

#include <cstdio>
#include <cstring>
#include <vector>
#include <algorithm>
using namespace std ;
#pragma comment(linker, "/STACK:1024000000,1024000000")
#define maxn 200050
struct E{
    int v , next ;
}edge[maxn] ;
int head[maxn] , cnt ;
struct node{
    int u , v , w ;
    int lca ;
}p[maxn] ;
int dep[maxn] , rmq[maxn][20] ;
int l[100010] , r[maxn] , cid ;
vector <int> vec[maxn] ;
int dp[maxn] , sum[maxn] ;
int c1[maxn] , c2[maxn] ;
void add_E(int u,int v) {
    edge[cnt].v = v ;
    edge[cnt].next = head[u] ; head[u] = cnt++ ;
    edge[cnt].v = u ;
    edge[cnt].next = head[v] ; head[v] = cnt++ ;
}
void dfs(int fa,int u) {
    l[u] = ++cid ;
    int i , j , v ;
    for(i = head[u] ; i != -1 ; i = edge[i].next) {
        v = edge[i].v ;
        if( v == fa ) continue ;
        dep[v] = dep[u] + 1 ;
        rmq[v][0] = u ;
        for(j = 1 ; j < 20 ; j++)
            rmq[v][j] = rmq[ rmq[v][j-1] ][j-1] ;
        dfs(u,v) ;
    }
    r[u] = ++cid ;
}
int lca(int u,int v) {
    if( dep[u] < dep[v] )
        swap(u,v) ;
    int i , j ;
    for(i = 19 ; i >= 0 ; i--) {
        if( dep[ rmq[u][i] ] >= dep[v] )
            u = rmq[u][i] ;
        if( u == v ) return u ;
    }
    for(i = 19 ; i >= 0 ; i--) {
        if( rmq[u][i] != rmq[v][i] ){
            u = rmq[u][i] ;
            v = rmq[v][i] ;
        }
    }
    return rmq[u][0] ;
}
int lowbit(int x) {
    return  x & -x ;
}
void add(int i,int k,int *c,int n) {
    while( i <= n ) {
        c[i] += k ;
        i += lowbit(i) ;
    }
}
int getsum(int i,int *c) {
    int ans = 0 ;
    while( i ) {
        ans += c[i] ;
        i -= lowbit(i) ;
    }
    return ans ;
}
void solve(int fa,int s,int n) {
    dp[s] = sum[s] = 0 ;
    int i , j , u , v , temp ;
    for(i = head[s] ; i != -1 ;i = edge[i].next) {
        v = edge[i].v ;
        if( v == fa ) continue ;
        solve(s,v,n) ;
        sum[s] += dp[v] ;
    }
    dp[s] = sum[s] ;
    for(i = 0 ; i < vec[s].size() ; i++) {
        u = p[ vec[s][i] ].u ;
        v = p[ vec[s][i] ].v ;
        temp = getsum(l[u],c1) + getsum(l[v],c1) - getsum(l[u],c2) - getsum(l[v],c2) + sum[s] ;
        dp[s] = max(dp[s],temp+p[vec[s][i]].w) ;
    }
    add(l[s],sum[s],c1,n*2) ;
    add(r[s],-sum[s],c1,n*2) ;
    add(l[s],dp[s],c2,n*2) ;
    add(r[s],-dp[s],c2,n*2) ;
}
void init(int n) {
    memset(head,-1,sizeof(head)) ;
    memset(rmq,0,sizeof(rmq)) ;
    memset(c1,0,sizeof(c1)) ;
    memset(c2,0,sizeof(c2)) ;
    cnt = cid = 0 ;
    dep[1] = 1 ;
    rmq[1][0] = 1  ;
    for(int i = 1 ; i <= n ; i++)
        vec[i].clear() ;
    return ;
}
int main() {
    int t , n , m ;
    int i , j , u , v , w ;
    //freopen("1006.in","r",stdin) ;
    //freopen("t.out","w",stdout) ;
    scanf("%d", &t) ;
    while( t-- ) {
        scanf("%d %d", &n, &m) ;
        init(n) ;
        for(i = 1 ; i < n ; i++) {
            scanf("%d %d", &u, &v) ;
            add_E(u,v) ;
        }
        dfs(-1,1) ;
        for(i = 0 ; i < m ; i++) {
            scanf("%d %d %d", &p[i].u, &p[i].v, &p[i].w) ;
            p[i].lca = lca(p[i].u,p[i].v) ;
            vec[ p[i].lca ].push_back(i) ;
        }
        solve(-1,1,n) ;
        printf("%d\n", dp[1]) ;
    }
    return 0 ;
}

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2025-01-13 14:06:09

hdu5293(2015多校1)--Tree chain problem(树状dp)的相关文章

HDU 5293 TREE CHAIN PROBLEM LCT+树形DP

题解链接 代码链接 链接 Tree chain problem Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others) Total Submission(s): 35    Accepted Submission(s): 8 Problem Description Coco has a tree, whose vertices are conveniently labeled by 1

HDU 5293 Tree chain problem

Tree chain problem Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others) Total Submission(s): 565    Accepted Submission(s): 137 Problem Description Coco has a tree, whose vertices are conveniently labeled by 1,2,-,n. Th

HDOJ 5293 Tree chain problem LCA+树链剖分+树形DP

[题意] 给定一颗树上的几条链和每条链的权值,求能取出的不含有公共节点的链的最大权值.... [解] 预处理每条链的lca 树形DP, d[i]表示取到这个节点时可以得到的最大值 , sum[i]=sigma( d[k] | k 是i的子节点) 如果不取i  d[i]=sum[i] 如果取i , e是lca为i的链则 d[i]=max(d[i],e的权值+sigma(sum[k])-sigma(d[k]))  k为树链上的点 可以用树链剖分+树装数组在nlogn的时间复杂度内求链上的值 Tree

hdu 5293 Tree chain problem(树链剖分+树形dp)

题目链接:hdu 5293 Tree chain problem 维护dp[u], sum[u],dp[u]表示以u为根节点的子树的最优值.sum[u]表示以u节点的所有子节点的dp[v]之和.对于边a,b,w,在LCA(a,b)节点的时候进行考虑.dp[u] = min{dp[u], Sum(a,b) - Dp(a,b) + sum[u] | (ab链上的点,不包括u } #pragma comment(linker, "/STACK:1024000000,1024000000")

HDU 5371(2015多校7)-Hotaru&#39;s problem(Manacher算法求回文串)

题目地址:HDU 5371 题意:给你一个具有n个元素的整数序列,问你是否存在这样一个子序列,该子序列分为三部分,第一部分与第三部分相同,第一部分与第二部分对称,如果存在求最长的符合这种条件的序列. 思路:用Manacher算法来处理回文串的长度,记录下以每一个-1(Manacher算法的插入)为中心的最大回文串的长度.然后从最大的开始穷举,只要p[i]-1即能得出以数字为中心的最大回文串的长度,然后找到右边对应的'-1',判断p[i]是不是大于所穷举的长度,如果当前的满足三段,那么就跳出,继续

Codeforces 459D Pashmak and Parmida&#39;s problem(树状数组)

题目链接:Codeforces 459D Pashmak and Parmida's problem 题目大意:给定一个序列,定义f(l,r,x)为l≤k≤r并且ak=x的k的个数,求1≤i<j≤n的情况下,f(1,i,ai)<f(j,n,aj)的个数. 解题思路:预处理出f(1,i,ai),f(j,n,aj)值,然后用树状数组维护个数. #include <cstdio> #include <cstring> #include <algorithm> us

Codeforcecs 459D Pashmak and Parmida&#39;s problem 树状数组 OR 分治

http://codeforces.com/contest/459/problem/D 题意:定义:f(l,r,x) [l,r]内x的个数 ,n个数,a[i] n<=1e5,a[i]<=1e9 问i<j时满足f(1,i,a[i]) > f(j,n,a[j]) 的(i,j)对数? 预处理出后缀f(j) 插入到BIT中 枚举i,查询mp[a[i]]-1,后更新BIT即可. #include <bits/stdc++.h> using namespace std; typed

poj2486--Apple Tree(树状dp)

Apple Tree Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 7789   Accepted: 2606 Description Wshxzt is a lovely girl. She likes apple very much. One day HX takes her to an apple tree. There are N nodes in the tree. Each node has an amoun

Codeforces Round 261 Div.2 D Pashmak and Parmida&#39;s problem --树状数组

题意:给出数组A,定义f(l,r,x)为A[]的下标l到r之间,等于x的元素数.i和j符合f(1,i,a[i])>f(j,n,a[j]),求有多少对这样的(i,j). 解法:分别从左到右,由右到左预处理到某个下标为止有多少个数等于该下标,用map维护. 然后树状数组更新每个f(j,n,a[j]),预处理完毕,接下来,从左往右扫过去,每次从树状数组中删去a[i],因为i != j,i不能用作后面的统计,然后统计getsum(inc[a[i]]-1), (inc表示从左到右),即查询比此时的a[i]