标签:
[题意]
给定一颗树上的几条链和每条链的权值,求能取出的不含有公共节点的链的最大权值....
[解]
预处理每条链的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的时间复杂度内求链上的值
1 7 3 1 2 1 3 2 4 2 5 3 6 3 7 2 3 4 4 5 3 6 7 3
6HintStack expansion program: #pragma comment(linker, "/STACK:1024000000,1024000000")
/* ***********************************************
Author :CKboss
Created Time :2015年07月22日 星期三 15时46分03秒
File Name :HDOJ5293.cpp
************************************************ */
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <string>
#include <cmath>
#include <cstdlib>
#include <vector>
#include <queue>
#include <set>
#include <map>
#pragma comment(linker, "/STACK:1024000000,1024000000")
using namespace std;
const int maxn=100100;
int n,m;
/**********************CHAIN***********************/
struct Chain
{
int from,to,weight;
}chain[maxn];
/// chain lca at pos i
vector<int> vi[maxn];
/**********************EDGE*************************/
struct Edge
{
int to,next;
}edge[maxn*2];
int Adj[maxn],Size;
void init()
{
memset(Adj,-1,sizeof(Adj)); Size=0;
for(int i=0;i<=n;i++) vi[i].clear();
}
void Add_Edge(int u,int v)
{
edge[Size].to=v;
edge[Size].next=Adj[u];
Adj[u]=Size++;
}
/**********************LCA**************************/
const int DEG=22;
int fa[maxn][DEG];///fa[i][j]i号节点的第2^j的祖先
int deg[maxn];///深度
void BFS(int root)
{
queue<int> q;
deg[root]=0;
fa[root][0]=root;
q.push(root);
while(!q.empty())
{
int u=q.front(); q.pop();
for(int i=1;i<DEG;i++)
{
fa[u][i]=fa[fa[u][i-1]][i-1];
}
for(int i=Adj[u];~i;i=edge[i].next)
{
int v=edge[i].to;
if(v==fa[u][0]) continue;
deg[v]=deg[u]+1;
fa[v][0]=u;
q.push(v);
}
}
}
int LCA(int u,int v)
{
if(deg[u]>deg[v]) swap(u,v);
int hu=deg[u],hv=deg[v];
int tu=u,tv=v;
for(int det=hv-hu,i=0;det;i++,det=det/2)
if(det&1)
tv=fa[tv][i];
if(tu==tv) return tu;
for(int i=DEG-1;i>=0;i--)
{
if(fa[tu][i]==fa[tv][i])
continue;
tu=fa[tu][i];
tv=fa[tv][i];
}
return fa[tu][0];
}
/************************树链剖分******************/
int Fa[maxn],deep[maxn],num[maxn],son[maxn];
int top[maxn],p[maxn],rp[maxn],pos;
int tree1[maxn],tree2[maxn];
int ans;
void INIT()
{
init();
pos=1; ans=0;
memset(son,-1,sizeof(son));
memset(tree1,0,sizeof(tree1));
memset(tree2,0,sizeof(tree2));
}
void dfs1(int u,int pre,int d)
{
num[u]=1; Fa[u]=pre; deep[u]=d;
for(int i=Adj[u];~i;i=edge[i].next)
{
int v=edge[i].to;
if(v==pre) continue;
dfs1(v,u,d+1);
num[u]+=num[v];
if((son[u]==-1)||(num[son[u]]<num[v])) son[u]=v;
}
}
void getPOS(int u,int to)
{
top[u]=to; p[u]=pos++; rp[p[u]]=u;
if(son[u]!=-1) getPOS(son[u],to);
for(int i=Adj[u];~i;i=edge[i].next)
{
int v=edge[i].to;
if(v!=Fa[u]&&v!=son[u]) getPOS(v,v);
}
}
// array
inline int lowbit(int x) { return x&(-x); }
void Add(int* tree,int p,int v)
{
for(int i=p;i<maxn;i+=lowbit(i)) tree[i]+=v;
}
int _sum(int* tree,int p)
{
int sum=0;
for(int i=p;i;i-=lowbit(i)) sum+=tree[i];
return sum;
}
int Query(int* tree,int L,int R)
{
return _sum(tree,R)-_sum(tree,L-1);
}
// query sum of node on the chain
int get_chain_sum(int u,int v)
{
int f1=top[u],f2=top[v];
// ret1: sum of sum tree1
// ret2: sum of d tree2
int ret1=0,ret2=0;
while(f1!=f2)
{
if(deep[f1]<deep[f2]) { swap(f1,f2); swap(u,v); }
//ret+=
ret1+=Query(tree1,p[f1],p[u]);
ret2+=Query(tree2,p[f1],p[u]);
u=Fa[f1]; f1=top[u];
}
if(deep[u]>deep[v]) swap(u,v);
//ret+=
ret1+=Query(tree1,p[u],p[v]);
ret2+=Query(tree2,p[u],p[v]);
return ret1-ret2;
}
// add one point on the node of the chain
void update(int* tree,int x,int v)
{
Add(tree,p[x],v);
}
int d[maxn],sum[maxn];
void DFS(int u,int fa)
{
sum[u]=0;
for(int i=Adj[u];~i;i=edge[i].next)
{
int v=edge[i].to;
if(v==fa) continue;
DFS(v,u);
sum[u]+=d[v];
}
/// not choose u;
d[u]=sum[u];
update(tree1,u,sum[u]);
/// choose u
for(int i=0,sz=vi[u].size();i<sz;i++)
{
int p=vi[u][i];
int w=chain[p].weight,from=chain[p].from,to=chain[p].to;
int temp=w+get_chain_sum(from,to);
d[u]=max(d[u],temp);
}
if(ans<d[u]) ans=d[u];
update(tree2,u,d[u]);
}
int main()
{
//freopen("in.txt","r",stdin);
//freopen("out.txt","w",stdout);
int T_T;
scanf("%d",&T_T);
while(T_T--)
{
scanf("%d%d",&n,&m);
INIT();
for(int i=0,u,v;i<n-1;i++)
{
scanf("%d%d",&u,&v);
Add_Edge(u,v); Add_Edge(v,u);
}
BFS(1);
for(int i=0,u,v,w;i<m;i++)
{
scanf("%d%d%d",&u,&v,&w);
//chain[i]=(Chain){u,v,w};
chain[i].from=u; chain[i].to=v; chain[i].weight=w;
int lca=LCA(u,v);
vi[lca].push_back(i);
}
dfs1(1,1,0); getPOS(1,1);
DFS(1,1);
printf("%d\n",ans);
}
return 0;
}
版权声明:本文为博主原创文章,未经博主允许不得转载。
HDOJ 5293 Tree chain problem LCA+树链剖分+树形DP
标签:
原文地址:http://blog.csdn.net/ck_boss/article/details/47017093