zoukankan      html  css  js  c++  java
  • 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;
    }
  • 相关阅读:
    Dubbo探索(七)
    Dubbo探索(六)
    Dubbo探索(五)
    Dubbo探索(四)
    Redis主节点内存占用过高
    修改RedHat 7.2 进程最大句柄数限制
    Linux 数据分析常用 shell命令
    流处理
    根域名服务器
    并发与并行(concurrency vs parallesim)
  • 原文地址:https://www.cnblogs.com/qscqesze/p/5273104.html
Copyright © 2011-2022 走看看