HDU5293 树链剖分+树形DP

=-=抓住叶节点往上揪

Tree chain problem

Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 1752    Accepted Submission(s): 561

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")

#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<cstdio>
#include<cstring>
#include<vector>
#include<algorithm>
using namespace std;
const int maxn=1e5+88;
int fa[maxn],dep[maxn],size[maxn],pos[maxn],bl[maxn],head[maxn];
int sum[maxn];
int dp[maxn],su[maxn],n,m;
vector<int>G[maxn];
struct node{
   int to,next;
}edge[maxn<<1];
struct cst{
   int x,y,z;
}road[maxn];
int tot,sz;
void init(){
   tot=sz=0;
   memset(sum,0,sizeof(sum));
   memset(head,-1,sizeof(head));
   for(int i=1;i<=n;++i) G[i].clear();
}
void add(int u,int v) {
   edge[tot].to=v;
   edge[tot].next=head[u];
   head[u]=tot++;
}
void sadd(int u,int val) {
   for( ; u<=n;u+=u&(-u))
    sum[u]+=val;
}
int getsum(int u) {
    int ret=0;
   for(;u;u-=u&(-u))
    ret+=sum[u];
   return ret;
}
void dfs1(int x){
    size[x]=1;
    for(int i=head[x];i+1;i=edge[i].next){
        int v=edge[i].to;
        if(v==fa[x]) continue;
        fa[v]=x;
        dep[v]=dep[x]+1;
        dfs1(v);
        size[v]+=size[x];
    }
}
void dfs2(int x,int chain)
{
    bl[x]=chain;
    pos[x]=++sz;
    int k=0;
    for(int i=head[x];i+1;i=edge[i].next){
        int v=edge[i].to;
        if(dep[v]>dep[x]&&size[v]>size[k])
            k=v;
    }
    if(!k) return;
    dfs2(k,chain);
    for(int i=head[x];i+1;i=edge[i].next)
        if(dep[edge[i].to]>dep[x]&&edge[i].to!=k)
        dfs2(edge[i].to,edge[i].to);
}
int LCA(int x,int y){
   while(bl[x]!=bl[y]) {
    if(dep[bl[x]]<dep[bl[y]]) swap(x,y);
    x=fa[bl[x]];
   }
   if(pos[x]>pos[y]) swap(x,y);
   return x;
}
int query(int x,int y){
    int ret=0;
   while(bl[x]!=bl[y]){
    if(dep[bl[x]]<dep[bl[y]]) swap(x,y);
    ret+=getsum(pos[x])-getsum(pos[bl[x]]-1);
    x=fa[bl[x]];
   }
   if(dep[x]>dep[y]) swap(x,y);
   ret+=getsum(pos[y])-getsum(pos[x]-1);
   return ret;
}
void solve(int u){
   su[u]=0;
   for(int i=head[u];i+1;i=edge[i].next){
    int v=edge[i].to;
    if(v==fa[u]) continue;
    solve(v);
    su[u]+=dp[v];
   }
   dp[u]=su[u];
   for(int i=0;i<(int)G[u].size();++i){
    int v=G[u][i];
    dp[u]=max(dp[u],query(road[v].x,road[v].y)+su[u]+road[v].z);
   }
   sadd(pos[u],su[u]-dp[u]);
}
int main(){
   int t,u,v;
   for(scanf("%d",&t);t--;){
    scanf("%d%d",&n,&m);
    init();
    for(int i=1;i<n;++i){
        scanf("%d%d",&u,&v);
        add(u,v);
        add(v,u);
    }
    dfs1(1);
    dfs2(1,1);
    for(int i=1;i<=m;++i)
    {
        scanf("%d%d%d",&road[i].x,&road[i].y,&road[i].z);
        G[LCA(road[i].x,road[i].y)].push_back(i);
    }
    solve(1);
    printf("%d\n",dp[1]);
   }
}

时间: 2024-08-09 02:20:41

HDU5293 树链剖分+树形DP的相关文章

(中等) HDU 5293 Tree chain problem,树链剖分+树形DP。

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

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")

树链剖分——树形到线性的转化

树链剖分: 树上操作并不能实现一段链的直接更新. 树链剖分就解决了这个问题. 本质上是树形到线性的转化. 通过子树,重链是一个连续的dfn区间的优秀性质,可以在dfn序列上进行操作,达到在树上操作的目的. 通常和线段树结合. 板子:以前写的. 树链剖分 例题: 1.遥远的国度 题目大意: 给定一棵有根树,每个点有一个权值,提供三种操作: 1.将x节点变为根节点 2.将x到y路径上的点的权值全部改为v 3.询问x的子树中点权的最小值 如果根不变,那么2.3就直接做了. 但是根变化了,随之第三问,子

CF1111E Tree 树链剖分,DP

CF1111E Tree 过年了,洛咕还没爬这次的题,先放个CF的链接吧. 对于每个询问点\(x\),设它的祖先即不能和它放在同一个集合中的点的个数为\(f[x]\),设\(dp[i][j]\)表示前\(i\)个询问点放在\(j\)个非空集合中的方案数,注意这里"前\(i\)个"的意义,这表示会对第\(i\)个点造成影响的点都已被考虑过了,转移就是\(dp[i][j] = dp[i - 1][j] * (i - f[j]) + dp[i -1][j - 1]\). 下面的问题就是怎么处

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]+s

[bzoj4712] 洪水 [树链剖分+线段树+dp]

题面 传送门 思路 DP方程 首先,这题如果没有修改操作就是sb题,dp方程如下 $dp[u]=max(v[u],max(dp[v]))$,其中$v$是$u$的儿子 我们令$g[u]=max(dp[v])$ 修改? 我们发现,本题中所有的修改都是非负的 也就是说,每一次修改结束以后,$dp[u]$的值只增不减 同时,修改$u$位置的$v[u]$值,只会影响到$u$到根的这一条链上的$dp$值 我们考虑修改后,这条链上的每个点的$dp[u]$值的增量,令这个增量为$delta[u]$ 那么显然当$

树链剖分[模板](洛谷 P3384)

洛谷·[模板]树链剖分 写在前面 首先,在学树链剖分之前最好先把 LCA.树形DP.DFS序 这三个知识点学了 如果这三个知识点没掌握好的话,树链剖分难以理解也是当然的. 树链剖分 树链剖分 就是对一棵树分成几条链,把树形变为线性,减少处理难度 概念 dfs1() dfs2() 对剖过后的树建线段树 处理问题 概念 重儿子:对于每一个非叶子节点,它的儿子中 儿子数量最多的那一个儿子 为该节点的重儿子 轻儿子:对于每一个非叶子节点,它的儿子中 非重儿子 的剩下所有儿子即为轻儿子 叶子节点没有重儿子

bzoj2843: 极地旅行社 离线+树链剖分

离线建树,树链剖分. #include<bits/stdc++.h> #define N 100010 #define M (l+r>>1) #define P (k<<1) #define S (k<<1|1) #define L l,M,P #define R M+1,r,S #define Z int l=1,int r=n,int k=1 using namespace std; int n,m; struct edge{ edge* s; int