hdu5293 Tree chain problem 树形dp+线段树

时间:2022-09-07 17:20:52

题目:

pid=5293">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+线段树的更多相关文章

  1. &lbrack;HDU 5293&rsqb;Tree chain problem&lpar;树形dp&plus;树链剖分&rpar;

    [HDU 5293]Tree chain problem(树形dp+树链剖分) 题面 在一棵树中,给出若干条链和链的权值,求选取不相交的链使得权值和最大. 分析 考虑树形dp,dp[x]表示以x为子树 ...

  2. HDU 5293 Tree chain problem 树形dp&plus;dfs序&plus;树状数组&plus;LCA

    题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=5293 题意: 给你一些链,每条链都有自己的价值,求不相交不重合的链能够组成的最大价值. 题解: 树形 ...

  3. HDU 5293 Tree chain problem 树形DP

    题意: 给出一棵\(n\)个节点的树和\(m\)条链,每条链有一个权值. 从中选出若干条链,两两不相交,并且使得权值之和最大. 分析: 题解 #include <cstdio> #incl ...

  4. Codeforces 671D&period; Roads in Yusland(树形DP&plus;线段树)

    调了半天居然还能是线段树写错了,药丸 这题大概是类似一个树形DP的东西.设$dp[i]$为修完i这棵子树的最小代价,假设当前点为$x$,但是转移的时候我们不知道子节点到底有没有一条越过$x$的路.如果 ...

  5. poj3162(树形dp&plus;线段树求最大最小值)

    题目链接:https://vjudge.net/problem/POJ-3162 题意:给一棵树,求每个结点的树上最远距离,记为a[i],然后求最大区间[l,r]满足区间内的max(a[i])-min ...

  6. POJ 3162 Walking Race 树形DP&plus;线段树

    给出一棵树,编号为1~n,给出数m 漂亮mm连续n天锻炼身体,每天会以节点i为起点,走到离i最远距离的节点 走了n天之后,mm想到知道自己这n天的锻炼效果 于是mm把这n天每一天走的距离记录在一起,成 ...

  7. Codeforces Round &num;530 &lpar;Div&period; 2&rpar; F &lpar;树形dp&plus;线段树)

    F. Cookies 链接:http://codeforces.com/contest/1099/problem/F 题意: 给你一棵树,树上有n个节点,每个节点上有ai块饼干,在这个节点上的每块饼干 ...

  8. HDU5293 &colon; Tree chain problem

    问题即:选择价值和最多的链,使得每个点最多被一条链覆盖. 那么考虑其对偶问题:选择最少的点(每个点可以重复选),使得每条链上选了至少$w_i$个点. 那么将链按照LCA的深度从大到小排序,每次若发现点 ...

  9. 【洛谷5298】&lbrack;PKUWC2018&rsqb; Minimax(树形DP&plus;线段树合并)

    点此看题面 大致题意: 有一棵树,给出每个叶节点的点权(互不相同),非叶节点\(x\)至多有两个子节点,且其点权有\(p_x\)的概率是子节点点权较大值,有\(1-p_x\)的概率是子节点点权较小值. ...

随机推荐

  1. c&num;动态调用Webservices

    方式一: Hashtable ht = new Hashtable(); ht.Add("a", "testhelloworld"); XmlDocument ...

  2. iOS&colon; Crash文件解析&lpar;一&rpar;

    iOS Crash文件的解析(一) 开发程序的过程中不管我们已经如何小心,总是会在不经意间遇到程序闪退.脑补一下当你在一群人面前自信的拿着你的App做功能预演的时候,流畅的操作被无情地Crash打断. ...

  3. 使用JDBC批量保存数据(JdbcDaoSupport,JdbcTemplete)

    最近做的一个项目中用到了Hibernate的,然后数据库批量插入数据的时候就使用到了hibernate的批处理,但是效率比较低,看网上说还有一些限制,要禁止二级缓存,还要多一个batch_size的配 ...

  4. oracle 数据导入导出命令

    1.数据导出:  1 将数据库TEST完全导出,用户名system 密码manager 导出到D:\daochu.dmp中   exp system/manager@TEST file=d:\daoc ...

  5. QT 内存泄露 检测

      一:问题出现     最近几天在做一个QT程序,IPX的检测控制程序.需要全天候运行.自己做完了,然后就运行.使用  top|grep TP2  来动态检测程序的CPU,内存占用律.不幸的是,一晚 ...

  6. TCP 连接的要点

    概念 TIME_WAIT: socket 仍然有数据在内核中待发送直到发送成功或超时,此socket不能被内核删除,同时等待是否要重传Ack对端还已发过来的FIN Linger Time:socket ...

  7. 【LeetCode每天一题】Jump Game II&lpar;跳跃游戏II&rpar;

    Given an array of non-negative integers, you are initially positioned at the first index of the arra ...

  8. 九、Brideg 桥接模式

    设计原理: 代码清单: 抽象类 DisplayImpl public abstract class DisplayImpl { public abstract void rawOpen(); publ ...

  9. 16,EasyNetQ-群集支持

    EasyNetQ支持RabbitMQ群集,无需部署负载均衡器. 只需在连接字符串中列出群集的节点... var bus = RabbitHutch.CreateBus("host=ubunt ...

  10. redis 持久化与备份策略

    持久化(persistence) 本文是 Redis 持久化文档 的中文翻译. 这篇文章提供了 Redis 持久化的技术性描述,推荐所有 Redis 用户阅读. 要更广泛地了解 Redis 持久化,以 ...