树上DP题。

其实有点类似于01的问题。方程很容易想到。首先,因为一条链的节点其实都是在树上的,所以很容易想到应该先求一个LCA。然后,当某节点不是链的LCA时,它的转移就是:

dp[i]=sum[i],其中,sum[i]是i的子节点的dp[i]的和。

如果它是某个点的LCA时,那么它的转移就是dp[i]=val[p]+(sum(sum[k])-sum(dp[k except i])),k是一条chain上的节点。

然而,这样做是不会过的,TLE。。。

树状数组维和chain上的节点的和。QAQ.....

怎么样维护呢?首先,使用DFS把树处理成DFS序,并维护时间戳,这是很显然的,记为l[u],r[u]。然后,假设对于某条链的LCA为u,计算出sum[u]和dp[u]后,对l[u]~r[u]进行区间更新。为什么要区间更新呢?因为,如果以后存在一条chain的起点是在u的子树内,那么,我们在计算链上节点和时,该链必定是经过u点的,这样,求前缀和就可以得到一个和是包含了u点的。区间更新,单点查询。单点查询就是完成了从起或终点到它们的LCA的链上节点求和,因为每次区间更新的时候,因为起点都在子树内,就可以对链上的节点的和不停地累加。

我弱菜没想到优化,TLE的代码。。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
#pragma comment(linker, "/STACK:1024000000,1024000000")
using namespace std; const int MAX=100010; struct Point{
int v,i;
Point(int vv,int ii){
v=vv,i=ii;
}
}; vector<Point>chain[MAX];
vector<int>head_chain[MAX];
//vector<int>chain_point;
int chain_from[MAX],chain_to[MAX],chain_val[MAX];
int pre[MAX]; struct Edge{
int u,v,next;
}edge[MAX*2];
int head[MAX],tot,n,m;
int sum[MAX],dp[MAX];
int parent[MAX],depth[MAX];
bool color[MAX]; void addedge(int u,int v){
edge[tot].u=u;
edge[tot].v=v;
edge[tot].next=head[u];
head[u]=tot++;
} int get_point(int i){
// chain_point.clear();
int res=0;
int u=chain_from[i],v=chain_to[i];
if(depth[u]<depth[v]) swap(u,v);
while(depth[u]>depth[v]){
// chain_point.push_back(u);
res+=(sum[u]-dp[u]);
u=parent[u];
}
while(u!=v){
// chain_point.push_back(u);
// chain_point.push_back(v);
res+=(sum[u]-dp[u]);
res+=(sum[v]-dp[v]);
u=parent[u];
v=parent[v];
}
res+=sum[u];
// chain_point.push_back(u);
return res;
} void dfs(int u,int par){
sum[u]=0;
for(int e=head[u];e!=-1;e=edge[e].next){
int v=edge[e].v;
if(v!=par){
dfs(v,u);
sum[u]+=dp[v];
}
}
dp[u]=sum[u];
if(head_chain[u].size()){
int sz=head_chain[u].size();
int tmp,index,tsz;
for(int i=0;i<sz;i++){
index=head_chain[u][i];
tmp=get_point(index);
// tmp=0; tsz=chain_point.size();
// for(int k=0;k<tsz;k++){
// tmp+=(sum[chain_point[k]]-dp[chain_point[k]]);
// }
dp[u]=max(dp[u],tmp+chain_val[index]);
}
}
} int findx(int u){
int x=u;
while(pre[u]!=-1){
u=pre[u];
}
while(pre[x]!=-1){
int t=pre[x];
pre[x]=u;
x=t;
}
return u;
} void DFS(int u,int par,int dep){
parent[u]=par;
depth[u]=dep;
for(int e=head[u];e!=-1;e=edge[e].next){
int v=edge[e].v;
if(v!=par){
DFS(v,u,dep+1);
pre[findx(v)]=u;
}
}
color[u]=true;
int sz=chain[u].size(),v;
for(int i=0;i<sz;i++){
v=chain[u][i].v;
if(color[v]){
head_chain[findx(v)].push_back(chain[u][i].i);
}
}
} /*
void get_head(int i){
int u=chain_from[i],v=chain_to[i];
if(depth[u]<depth[v]) swap(u,v);
while(depth[u]>depth[v]){
u=parent[u];
}
while(u!=v){
u=parent[u],v=parent[v];
}
head_chain[u].push_back(i);
}
*/
int main(){
int T,u,v;
scanf("%d",&T);
while(T--){
scanf("%d%d",&n,&m);
tot=0;
memset(head,-1,sizeof(head));
memset(pre,-1,sizeof(pre));
memset(color,false,sizeof(color));
for(int i=1;i<n;i++){
scanf("%d%d",&u,&v);
addedge(u,v);
addedge(v,u);
head_chain[i].clear();
chain[i].clear();
}
chain[n].clear();
head_chain[n].clear();
for(int i=1;i<=m;i++){
scanf("%d%d%d",&chain_from[i],&chain_to[i],&chain_val[i]);
chain[chain_from[i]].push_back(Point(chain_to[i],i));
chain[chain_to[i]].push_back(Point(chain_from[i],i));
// get_head(i);
}
DFS(1,1,1);
dfs(1,0);
printf("%d\n",dp[1]);
}
return 0;
}

http://blog.csdn.net/qq_24451605/article/details/47003497

简单的代码,其实写起来真的不难,主要是优化没想到。。。。

#pragma comment(linker, "/STACK:1024000000,1024000000")
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <vector>
#define MAX 200007 using namespace std; int n,m,t; typedef long long LL; LL d[MAX];
LL sum[MAX]; LL c1[MAX<<1];
LL c2[MAX<<1]; int lowbit ( int x )
{
return x&-x;
} void add1 ( int x , LL v )
{
while ( x <= n )
{
c1[x] += v;
x += lowbit ( x );
}
} void add2 ( int x , LL v )
{
while ( x <= n )
{
c2[x] += v;
x += lowbit ( x );
}
} LL sum1 ( int x )
{
LL res = 0;
while ( x )
{
res += c1[x];
x -= lowbit ( x );
}
return res;
} LL sum2 ( int x )
{
LL res = 0;
while ( x )
{
res += c2[x];
x -= lowbit ( x );
}
return res;
} typedef pair<int,int> PII; vector<int> e[MAX];
vector<int> chain[MAX];
vector<PII> a[MAX];
vector<LL> w[MAX];
vector<LL> val[MAX]; int fa[MAX];
int times;
bool used[MAX];
int l[MAX];
int r[MAX]; int _find ( int x )
{
return fa[x] == x ? x: fa[x] = _find ( fa[x]);
} void LCA ( int u )
{
fa[u] = u;
l[u] = ++times;
used[u] = true;
for ( int i = 0 ; i < e[u].size() ; i++ )
{
int v = e[u][i];
if ( used[v] ) continue;
LCA ( v );
fa[v] = u;
}
for ( int i = 0 ; i < chain[u].size() ; i++ )
{
int v = chain[u][i];
if ( !used[v] ) continue;
int x = _find ( v );
a[x].push_back ( make_pair ( u , v ));
w[x].push_back ( val[u][i] );
}
r[u] = ++times;
} void dfs ( int u , int p )
{
sum[u] = 0;
d[u] = 0;
for ( int i = 0 ; i < e[u].size() ; i++ )
{
int v = e[u][i];
if ( v == p ) continue;
dfs ( v , u );
sum[u] += d[v];
}
for ( int i = 0 ; i < a[u].size() ; i++ )
{
int x = a[u][i].first;
int y = a[u][i].second;
LL temp = sum1(l[x]) + sum1(l[y]) + sum[u]
-sum2(l[x]) - sum2(l[y]);
d[u] = max ( temp + w[u][i] , d[u] );
}
d[u] = max ( d[u] , sum[u] );
add1 ( l[u] , sum[u] );
add1 ( r[u] , -sum[u] );
add2 ( l[u] , d[u] );
add2 ( r[u] , -d[u] );
} void init ( )
{
times = 0;
memset ( c1 , 0 , sizeof ( c1 ) );
memset ( c2 , 0 , sizeof ( c2 ));
memset ( used , 0 , sizeof ( used ));
for ( int i = 0 ; i < MAX ; i++ )
{
e[i].clear();
val[i].clear();
a[i].clear();
w[i].clear();
chain[i].clear();
}
} int main ( )
{
int u,v,x;
scanf ( "%d" , &t );
while ( t-- )
{
init();
scanf ( "%d%d" , &n , &m );
int nn = n-1;
while ( nn-- )
{
scanf ( "%d%d" , &u , &v );
e[u].push_back ( v );
e[v].push_back ( u );
}
n = n*2;
while ( m-- )
{
scanf ( "%d%d%d" , &u , &v , &x );
chain[u].push_back ( v );
chain[v].push_back ( u );
val[u].push_back ( x );
val[v].push_back ( x );
}
//cout <<"YES" << endl;
LCA ( 1 );
dfs ( 1, -1 );
printf ( "%I64d\n" , d[1] );
}
}

HDU 5293的更多相关文章

  1. [HDU 5293]Tree chain problem(树形dp+树链剖分)

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

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

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

  3. HDU 5293 Annoying problem 树形dp dfs序 树状数组 lca

    Annoying problem 题目连接: http://acm.hdu.edu.cn/showproblem.php?pid=5293 Description Coco has a tree, w ...

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

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

  5. codeforces 671D Roads in Yusland & hdu 5293 Tree chain problem

    dp dp优化 dfs序 线段树 算是一个套路.可以处理在树上取链的问题.

  6. HDU 5293 Tree chain problem

    树状数组 + dp 设$f_i$表示以$i$为根的子树中的能选取的最大和,$sum_x$表示$\sum_{f_y}$  ($y$是$x$的一个儿子),这样子我们把所有给出的链按照两点的$lca$分组, ...

  7. HDU 5293 Tree chain problem 树形DP

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

  8. 刷题总结——Tree chain problem(HDU 5293 树形dp+dfs序+树状数组)

    题目: Problem Description Coco has a tree, whose vertices are conveniently labeled by 1,2,…,n.There ar ...

  9. HDU 5293 Train chain Problem - 树链剖分(树状数组) + 线段树+ 树型dp

    传送门 题目大意: 一颗n个点的树,给出m条链,第i条链的权值是\(w_i\),可以选择若干条不相交的链,求最大权值和. 题目分析: 树型dp: dp[u][0]表示不经过u节点,其子树的最优值,dp ...

随机推荐

  1. OpenResty / Nginx模块,Lua库和相关资源的列表

    OpenResty / Nginx模块,Lua库和相关资源的列表 什么是OpenResty OpenResty是一个成熟的网络平台,它集成了标准的Nginx核心,LuaJIT,许多精心编写的Lua库, ...

  2. Win7 + VS2015 + Python3.6编译

    0. 下载安装hg. http://bitbucket.org/tortoisehg/files/downloads/tortoisehg-4.0.1-x64.msi 1. 下载Python3.6源代 ...

  3. JavaScript--innerHTML 属性

    innerHTML 属性用于获取或替换 HTML 元素的内容. 语法: Object.innerHTML 注意: 1.Object是获取的元素对象,如通过document.getElementById ...

  4. CTSC+APIO+THUACM游记

    退役之前,写点破事乐呵乐呵.. (同DaD3zZ) CTSC Day0 来到丽都 哈哈哈这可是四星级豪华酒店啊   想想要在这住7天  美滋滋 换了半天的房间 也没有换到一起   最后yzy& ...

  5. Android内存管理(11)*常见JVM回收机制「Java进程内存堆分代,JVM分代回收内存,三种垃圾回收器」

    参考: http://www.blogjava.net/rosen/archive/2010/05/21/321575.html 1,Java进程内存堆分代: 典型的JVM根据generation(代 ...

  6. vs2010 视图 aspx页面设计窗口创建控件时出错 未将对象引用设置到对象的实例

    第一步,首先关闭aspx页面 第二步,在单击项目右击,选择“清理” 第三步,然后在打开aspx页面,就可以看到正常的页面了. 注:一次不行的会,多做几次. 如果还是不行的话,你看看你.cs页面是否继承 ...

  7. MyBatis 配置控制台上显示sql语句(log4j.properties 之三)

    ### direct log messages to stdout ###log4j.appender.stdout=org.apache.log4j.ConsoleAppenderlog4j.app ...

  8. [ NOIP 1998 ] TG

    \(\\\) \(\#A\) 车站 火车从第\(1\)站开出,上车的人数为\(a\),然后到达第\(2\)站,在第\(2\)站有人上.下车,但上.下车的人数相同,因此在第\(2\)站开出时(即在到达第 ...

  9. Ajax应用查询员工信息

    首先要用上一篇的步骤启动服务器,建立站点.然后在该站点下创建php文件和html文件. php代码如下,文件名为server.php <?php //设置页面内容是html编码格式是utf-8 ...

  10. 【PostgreSQL-9.6.3】临时表

    PostgreSQL中的临时表分两种,一种是会话级临时表,一种是事务级临时表.在会话级临时表中,数据可以存在于整个会话的生命周期中,在事务级临时表中的数据只能存在于事务的生命周期中.1. 会话级临时表 ...