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

HDU 5293 Tree chain problem - 树形dp&树状数组优化

2016-02-18 21:24 501 查看
题目描述

题目大意:

给定一棵有 n 个点的树,以及 m 条树链,其中第 i 条树链 的价值为 wi,请选择一些没有公共点的树链,使得价值和最大。

1 ≤n,m≤ 100000。

Source:2015 Multi-University Training Contest 1

分析:

设f[u]为u为根的子树上选择没有公共点的树链所得的最大价值和。

转移方程:

枚举链的两端点的lca为u的链,记w为当前链的价值

f[u]=max{∑f[u.son],w+∑k为当前链上的节点的儿子f[k]}f[u]=max\{{\sum{f[u.son]} , w+\sum_{k为当前链上的节点的儿子}{f[k]}} \}

时间复杂度O((n+m)*n),过不了,选择优化,记sum[u]为u的所有儿子v的f[v]之和,得到:

f[u]=max{∑f[u.son],w+∑j为当前链上的节点sum[j]−f[j]}f[u]=max\{{\sum{f[u.son]} , w+\sum_{j为当前链上的节点}{sum[j]-f[j]}} \}

(链上的点会在它的父亲的sum[]中多加,要再减去)

可根据dfs序维护树状数组来实现优化。

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
using namespace std;
#define MAXN 100000
#define MAXM 100000
#define MAXLOG 20
typedef long long LL;

struct node{
int v;
node *next;
}edge[MAXN*2+10],*adj[MAXN+10],*ecnt=&edge[0];

vector<int> pnt[MAXN+10];
int n,m,LogN,chain[MAXM+10][3];
int fa[MAXN+10],dep[MAXN+10],P[MAXN+10][MAXLOG+10];
int in[MAXN+10],out[MAXN+10],cntd;
LL c[2*MAXN+10],f[MAXN+10];

void Init()
{
memset(adj,0,sizeof adj);
ecnt=&edge[0];
memset(pnt,0,sizeof pnt);
memset(fa,0,sizeof fa);
memset(dep,0,sizeof dep);
memset(f,0,sizeof f);
cntd=0;
memset(c,0,sizeof c);
}
void addedge(int u,int v)
{
node *p=++ecnt;
p->v=v;
p->next=adj[u];
adj[u]=p;
}
void dfs(int u,int prev,int L)
{
fa[u]=prev;
dep[u]=L;
for(node *p=adj[u];p;p=p->next){
if(p->v==fa[u]) continue;
dfs(p->v,u,L+1);
}
}
void LCA_pre()
{
memset(P,-1,sizeof P);
for(int i=1;i<=n;i++)
P[i][0]=fa[i];
for(LogN=0;(1<<LogN)<=n;LogN++);
LogN--;
for(int j=1;j<=LogN;j++){
for(int i=1;i<=n;i++)
if(P[i][j-1]!=-1)
P[i][j]=P[P[i][j-1]][j-1];
}
}
int LCA(int x,int y)
{
if(dep[x]<dep[y])
swap(x,y);
int Logx;
for(Logx=0;(1<<Logx)<=dep[x];Logx++);
Logx--;
for(int i=Logx;i>=0;i--)
if(dep[P[x][i]]>=dep[y])
x=P[x][i];
if(x==y) return x;
for(int i=Logx;i>=0;i--)
if(P[x][i]!=P[y][i])
x=P[x][i],y=P[y][i];
return fa[x];
}
void read()
{
int x,y;
scanf("%d%d",&n,&m);
for(int i=1;i<n;i++){
scanf("%d%d",&x,&y);
addedge(x,y);
addedge(y,x);
}
dfs(1,0,1);
LCA_pre();
for(int i=1;i<=m;i++){
scanf("%d%d%d",&chain[i][0],&chain[i][1],&chain[i][2]);
int lca=LCA(chain[i][0],chain[i][1]);
pnt[lca].push_back(i);
}
}
int lowbit(int x){
return x&(-x);
}
void Update(int x,LL d){
while(x<=2*n){
c[x]+=d;
x+=lowbit(x);
}
}
LL Getsum(int x){
LL ret=0;
while(x){
ret+=c[x];
x-=lowbit(x);
}
return ret;
}
void DP(int u) //dfs for dp on the tree
{
LL g_u=0;
in[u]=++cntd;
for(node *p=adj[u];p;p=p->next){
if(p->v==fa[u]) continue;
DP(p->v);
g_u+=f[p->v];
}
out[u]=++cntd;
Update(in[u],g_u);
Update(out[u]+1,-g_u);
f[u]=g_u;
int side=pnt[u].size();
for(int i=0,num;i<side;i++){
num=pnt[u][i];
f[u]=max(f[u],Getsum(out[chain[num][0]])+Getsum(out[chain[num][1]])+1LL*chain[num][2]-g_u);
}
Update(in[u],-f[u]);
Update(out[u]+1,f[u]);
}
int main()
{
int T;
scanf("%d",&T);
while(T--){
Init();
read();
DP(1);
printf("%I64d\n",f[1]);
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: