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

Annoying problem

题目连接:

http://acm.hdu.edu.cn/showproblem.php?pid=5293

Description

Coco has a tree, whose vertices are conveniently labeled by 1,2,…,n.
There are m chain on the tree, Each chain has a certain weight. Coco would like to pick out some chains any two of which do not share common vertices.
Find out the maximum sum of the weight Coco can pick

Input

The input consists of several test cases. The first line of input gives the number of test cases T (T<=10).
For each tests:
First line two positive integers n, m.(1<=n,m<=100000)
The following (n - 1) lines contain 2 integers ai bi denoting an edge between vertices ai and bi (1≤ai,bi≤n),
Next m lines each three numbers u, v and val(1≤u,v≤n,0<val<1000), represent the two end points and the weight of a tree chain.

Output

For each tests:
A single integer, the maximum number of paths.

Sample Input

1
7 3
1 2
1 3
2 4
2 5
3 6
3 7
2 3 4
4 5 3
6 7 3

Sample Output

6

Hint

题意

给你一棵树,树上有n个点。

然后给你m条链,然后让你选择一些不相交的链,使得权值和最大。(每条链都有权值)

题解:

树形dp+dfs序+树状数组

首先想到的一点用dp[i]表示以i为根的子树最大值。

所给你的链只用考虑在lca这个点拿。

一个辅助数组sum[i]表示i点儿子的所有dp值的和。

然后dp方程就很显然了:

1.如果i点不拿任何链,那么dp[i]=sum[i]

2.如果i点拿了一条链,那么dp[i]=sum[i]+dp[v]+w,dp[v]是以那条链中的某个节点为父亲的点的dp值。

比较显然的发现dp[v] = sum[k] - dp[k],k即为那条链上的点。

然后这个东西按照dfs序去维护一个树状数组就好了。

代码

#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<bits/stdc++.h>
using namespace std;
const int maxn = 2e5+7;
const int maxm = 25;
struct node
{
    int l,r,w;
    node(int l=0,int r=0,int w=0):l(l),r(r),w(w){}
};
vector<int>E[maxn];
vector<node>query[maxn];
int n,m,x,y,z,dp[maxn],in[maxn],out[maxn],deep[maxn],lca[maxn][maxm],cnt,sum[maxn];
struct Bit
{
    int a[maxn];
    void init(){memset(a,0,sizeof(a));}
    int lowbit(int x){return x&(-x);}
    void update(int x,int v)
    {
        for(int i=x;i<maxn;i+=lowbit(i))
            a[i]+=v;
    }
    int get(int x)
    {
        int ans=0;
        for(int i=x;i;i-=lowbit(i))
            ans+=a[i];
        return ans;
    }
}T;
void init()
{
    cnt=1;
    for(int i=0;i<maxn;i++)
        E[i].clear(),query[i].clear();
    T.init();
    memset(deep,0,sizeof(deep));
    memset(lca,0,sizeof(lca));
    memset(dp,0,sizeof(dp));
    memset(in,0,sizeof(in));
    memset(out,0,sizeof(out));
    memset(sum,0,sizeof(sum));
}
void dfs(int x,int p)
{
    in[x]=cnt++;
    for(int i=0;i<E[x].size();i++)
    {
        int v = E[x][i];
        if(v==p)continue;
        deep[v]=deep[x]+1;
        lca[v][0]=x;
        for(int j=1;j<maxm;j++)
        {
            int fa = lca[v][j-1];
            if(fa==0)continue;
            lca[v][j]=lca[fa][j-1];
        }
        dfs(v,x);
    }
    out[x]=cnt++;
}
int up(int x,int d)
{
    for(int i=maxm-1;i>=0;i--)
    {
        if(d<(1<<i))continue;
        x=lca[x][i];
        d-=(1<<i);
    }
    return x;
}
int Lca(int x,int y)
{
    if(deep[x]>deep[y])swap(x,y);
    y=up(y,deep[y]-deep[x]);
    if(x==y)return x;
    for(int i=maxm-1;i>=0;i--)
    {
        if(lca[x][i]!=lca[y][i])
            x=lca[x][i],y=lca[y][i];
    }
    return lca[x][0];
}
void dfs2(int x,int fa)
{
    for(int i=0;i<E[x].size();i++)
    {
        int v = E[x][i];
        if(v==fa)continue;
        dfs2(v,x);
        sum[x]+=dp[v];
    }
    dp[x]=sum[x];
    for(int i=0;i<query[x].size();i++)
    {
        int l=query[x][i].l;
        int r=query[x][i].r;
        int w=query[x][i].w;
        dp[x]=max(dp[x],sum[x]+T.get(in[r])+T.get(in[l])+w);
    }
    T.update(in[x],sum[x]-dp[x]),T.update(out[x],dp[x]-sum[x]);
}
void solve()
{
    init();
    scanf("%d%d",&n,&m);
    for(int i=1;i<n;i++)
    {
        scanf("%d%d",&x,&y);
        E[x].push_back(y);
        E[y].push_back(x);
    }
    dfs(1,0);
    for(int i=1;i<=m;i++)
    {
        scanf("%d%d%d",&x,&y,&z);
        query[Lca(x,y)].push_back(node(x,y,z));
    }
    dfs2(1,0);
    cout<<dp[1]<<endl;
}
int main()
{
    int t;scanf("%d",&t);
    while(t--)solve();
    return 0;
}
posted @ 2016-03-13 20:49  qscqesze  阅读(466)  评论(0编辑  收藏  举报