hdu5293 Tree chain problem
阿新 • • 發佈:2018-11-04
題目
題解
題意:有m條鏈,每條鏈連結兩個頂點,鏈存在一個權值w,現在想要挑選一些鏈,挑選的鏈中不能出現相同的節點,問可以挑選出的最大的權重是多少
Solution
設
為以第
個點位根節點的子樹的最優解,
表示表示
節點的所有子節點的
和(注意:不包括
)
1.第
個節點上不出現鏈,那麼
;
2.第
個節點上出現鏈,如果選擇加入這條鏈,那麼
Code
#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<bits/stdc++.h>
using namespace std;
const int N=100001;
#define M(a) memset(a,0,sizeof(a))
int l[N],r[N],dp[N],sum[N],c1[N<<1],c2[N<<1],x,y,fa[N][19],tot,h[N],T,n,m,cnt,dep[N],i,lca,z;
struct node{
int to,ne;
}e[N<<1];
struct kk{
int u,v,w;
};
vector<kk>p[N];
void addedge(int x,int y){
e[++tot]=(node){y,h[x]};
h[x]=tot;
}
int get(int x,int *c){
int s=0;
for (;x;x^=x&-x) s+=c[x];
return s;
}
void add(int x,int y,int *c){
for (;x<=n*2;x+=x&-x) c[x]+=y;
}
void dfs1(int u,int f){
l[u]=++cnt;
fa[u][0]=f;
for (int i=1;i<19;i++) fa[u][i]=fa[fa[u][i-1]][i-1];
for (int i=h[u],v;i;i=e[i].ne)
if ((v=e[i].to)!=f) dep[v]=dep[u]+1,dfs1(v,u);
r[u]=++cnt;
}
void dfs2(int u,int fa){
for (int i=h[u],v;i;i=e[i].ne)
if ((v=e[i].to)!=fa) dfs2(v,u),sum[u]+=dp[v];
dp[u]=sum[u];
for (int i=0;i<p[u].size();i++){
int x=p[u][i].u,y=p[u][i].v;
dp[u]=max(dp[u],get(l[x],c1)-get(l[x],c2)+get(l[y],c1)-get(l[y],c2)+p[u][i].w+sum[u]);
}
add(l[u],sum[u],c1);add(r[u],-sum[u],c1);
add(l[u],dp[u],c2);add(r[u],-dp[u],c2);
}
int LCA(int x,int y){
if (dep[x]<dep[y]) swap(x,y);
for (int i=18;i>=0;i--)
if (dep[fa[x][i]]>=dep[y]) x=fa[x][i];
if (x==y) return x;
for (int i=18;i>=0;i--)
if (fa[x][i]!=fa[y][i]) x=fa[x][i],y=fa[y][i];
return fa[x][0];
}
int main(){
scanf("%d",&T);
for (;T--;){
scanf("%d%d",&n,&m);
for (i=1;i<=n;i++) p[i].clear();
cnt=tot=0;
M(sum);M(dp);M(c1);M(c2);M(h);
for (i=1;i<n;i++) scanf("%d%d",&x,&y),addedge(x,y),addedge(y,x);
dep[0]=-1;
dfs1(1,0);
for (i=1;i<=m;i++){
scanf("%d%d%d",&x,&y,&z);
lca=LCA(x,y);
p[lca].push_back((kk){x,y,z});
}
dfs2(1,0);
printf("%d\n",dp[1]);
}
}