您的位置:首页 > 大数据 > 人工智能

[2015hdu多校联赛补题]hdu5293 Tree chain problem

2015-08-02 23:12 453 查看
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5293

题意:给你一棵n个点的树,和一些该树上的树链,每个树链有一定的权值,要求选出一些不相交的树链,使他们的权值和尽量大

解:

树形dp,dp[x]表示以x为根节点的子树的解,那么就可以基于在当前结点对树链的选和不选进行dp

现在有两个问题:

1、在树链上的哪个点进行选择?

2、选和不选分别如何操作?

对于第一个问题,粗略想一下(在解决问题二的时候会发现),树链上最浅的一个点(也就是树链两端的lca)上选择是可行的

对于第二个问题,(假设现在在点u)不选的话,dp[u]=Sum(dp[v])(v为u的子节点),用sum[u]记录Sum(dp[v])(v为u的子节点),有dp[u]=sum[u]

选择的话,对于每一个lca在u点的树链c,

dp[u]=max(dp[u],Sum(dp[v1])+c.w(v1为c上所有节点的子节点, c.w为该链的权值))

dp[u]=max(dp[u],Sum(sum[x])-Sum(dp[x])+c.w(x为c上所有节点, c.w为该链的权值))

这个链上所有节点的某值和,用dfs序+树状数组维护一下就好了

/*
* Problem:
* Author:  SHJWUDP
* Created Time:  2015/8/2 星期日 22:07:32
* File Name: 233.cpp
* State:
* Memo:
*/
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
#pragma comment(linker, "/STACK:1024000000,1024000000")

using namespace std;

struct Edge {
int u, v;
Edge(int u, int v):u(u), v(v){}
};
struct Chain {
int a, b, w;
int lca;
};
struct Fenwick {
int n;
vector<int> c;
void init(int n) {
this->n=n;
c.assign(n+1, 0);
}
int lowbit(int x) {
return x & -x;
}
void add(int x, int v) {
while(x<=n) {
c[x]+=v; x+=lowbit(x);
}
}
int getsum(int x) {
int res=0;
while(x>0) {
res+=c[x]; x-=lowbit(x);
}
return res;
}
} fw1, fw2;

int n, m;
vector<Edge> edges;
vector<vector<int> > G;
vector<Chain> chain;
vector<int> ln, rn, dep, dp, sum;
vector<vector<int> > fa, arr;
int root, cnt;
void init(int sz) {
edges.clear();
G.assign(sz, vector<int>(0));
chain.resize(sz);
ln.resize(sz); rn.resize(sz); dep.resize(sz); dp.resize(sz); sum.resize(sz);
fa.assign(sz, vector<int>(20));
arr.assign(sz, vector<int>(0));
fw1.init(sz<<1); fw2.init(sz<<1);
}
void addEdge(int u, int v) {
edges.push_back(Edge(u, v));
G[u].push_back(edges.size()-1);
}
void dfs1(int u) {
ln[u]=++cnt;
for(int k=1; k<20; k++) fa[u][k]=fa[fa[u][k-1]][k-1];
for(int i : G[u]) {
Edge & e=edges[i];
if(e.v==fa[u][0]) continue;
fa[e.v][0]=u;
dep[e.v]=dep[u]+1;
dfs1(e.v);
}
rn[u]=++cnt;
}
int lca(int u, int v) {
if(dep[u]<dep[v]) swap(u, v);
for(int k=19; k>=0; k--) {
if(dep[fa[u][k]]>=dep[v]) {
u=fa[u][k];
}
}
if(u==v) return u;
for(int k=19; k>=0; k--) {
if(fa[u][k]!=fa[v][k]) {
u=fa[u][k]; v=fa[v][k];
}
}
return fa[u][0];
}
void dfs2(int u) {
dp[u]=sum[u]=0;
for(int i : G[u]) {
Edge & e=edges[i];
if(e.v==fa[u][0]) continue;
dfs2(e.v);
sum[u]+=dp[e.v];
}
dp[u]=sum[u];
for(int i : arr[u]) {
Chain & c=chain[i];
int tmp=fw1.getsum(ln[c.a])+fw1.getsum(ln[c.b])
-fw2.getsum(ln[c.a])-fw2.getsum(ln[c.b])+sum[u];
dp[u]=max(dp[u], tmp+c.w);
}
fw1.add(ln[u], sum[u]); fw1.add(rn[u], -sum[u]);
fw2.add(ln[u], dp[u]); fw2.add(rn[u], -dp[u]);
}
int main() {
#ifndef ONLINE_JUDGE
freopen("in", "r", stdin);
//freopen("out", "w", stdout);
#endif
int T;
scanf("%d", &T);
while(T--) {
scanf("%d%d", &n, &m);
init(n+1);
for(int i=1; i<n; i++) {
int a, b;
scanf("%d%d", &a, &b);
addEdge(a, b);
addEdge(b, a);
}
root=1; cnt=0; dep[root]=0; fa[root][0]=root; dfs1(root);
for(int i=0; i<m; i++) {
scanf("%d%d%d", &chain[i].a, &chain[i].b, &chain[i].w);
chain[i].lca=lca(chain[i].a, chain[i].b);
arr[chain[i].lca].push_back(i);
}
dfs2(root);
printf("%d\n", dp[root]);
}
return 0;
}


hdu 5293
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: