HDU 5293 Tree chain problem(树形DP+树链剖分)

75 篇文章 0 订阅
21 篇文章 0 订阅

题意:一颗n节点树上有m条链,每条链有权重,求一个链的集合使权重和最大且两两不相交。

解析:令dp[i]为以i为根的子树的最大权重和。

如果i不在链上,则有dp[i] = sigma(dp[k]) k为i的子节点

如果i在某一条链(u,v,w)上,那么dp[i] = w + sigma(dp[k]) k为链上所有节点的子节点。对于该值,我们可以统计统计链上节点的所有子节点dp的和 - 链上节点dp和(经树链剖分后用树状数组维护)。


[code]:

#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<vector>

#define lson l , mid , rt<<1
#define rson mid+1, r, rt<<1|1
#define lowbit(i) (i&-i)
using namespace std;
const int maxn = 1e5+5;

inline bool read(int &ret){
    char c;int sgn;
    if(c = getchar(),c==EOF) return 0;
    while(c != '-'&&(c<'0'||c>'9')) c=getchar();
    sgn = (c=='-')?-1:1;
    ret = (c=='-')?0:(c-'0');
    while(c=getchar(),c>='0'&&c<='9') ret=ret*10+(c-'0');
    ret*=sgn;
    return 1;
}

struct Chain{
    int u,v,w;
    Chain(int u,int v,int w):u(u),v(v),w(w){}
};
struct Nod{
    int b,next;
    void init(int b,int next){
        this->b=b;this->next=next;
    }
}buf[2*maxn];
int n,m,len,E[maxn];
vector<Chain> G[maxn];

struct LCA{
    int rmq[maxn<<1],pos[maxn<<3];
    int F[maxn<<1],P[maxn],lca;

    void dfs(int u,int pre,int deep){
        int i,v;
        lca++;F[lca]=u;P[u]=lca;rmq[lca]=deep;
        for(i=E[u];i!=-1;i=buf[i].next){
            v = buf[i].b;
            if(v == pre) continue;
            dfs(v,u,deep+1);
            lca++;F[lca]=u;rmq[lca]=deep;
        }
    }
    void build(int l,int r,int rt){
        if(l == r) { pos[rt] = l; return; }
        int mid = (l + r) >> 1;
        build(lson);build(rson);
        pos[rt] = rmq[pos[rt<<1]] < rmq[pos[rt<<1|1]]? pos[rt<<1]:pos[rt<<1|1];
    }
    int query(int a,int b,int l,int r,int rt){
        if(l > b || r < a) return 0;
        if(a <= l && r <= b) return pos[rt];
        int o1,o2,mid = (l + r) >>1;
        o1 = query(a,b,lson);o2 = query(a,b,rson);
        return rmq[o1] < rmq[o2] ? o1 : o2;
    }
    void make(int root){
        lca = 0;
        memset(rmq,63,sizeof(rmq));
        dfs(root,-1,0);
        build(1,lca,1);
    }
    int ancestor(int a,int b){
        int ca = P[a],cb = P[b];
        if(ca > cb) swap(ca,cb);
        return F[query(ca,cb,1,lca,1)];
    }
}ac;


int dp[maxn];
int num[maxn],dep[maxn],par[maxn],son[maxn],head[maxn],P[maxn],cnt;

struct BIT{
    int bit[2][maxn],range;
    void init(int range){
        this->range = range;
        for(int i = 1;i <= range;i++) bit[0][i] = bit[1][i] = 0;
    }
    void add(int k,int x,int id){
        for(;k<=range;k+=lowbit(k)) bit[id][k]+=x;
    }
    int sum(int k,int id){
        int res = 0;
        for(;k;k-=lowbit(k)) res += bit[id][k];
        return res;
    }
    int query(int l,int r,int id){
        return sum(r,id)-sum(l-1,id);
    }
}bt;

void init(){
    len = cnt = 0;
    memset(E,-1,n*sizeof(int));
    for(int i = 0;i < n;i++) G[i].clear();
}
void add_edge(int a,int b){
    buf[len].init(b,E[a]);E[a]=len++;
    buf[len].init(a,E[b]);E[b]=len++;
}
void dfs(int u,int pre){
    int i,v;
    num[u] = 1;son[u] = -1;par[u] = pre;dep[u] = pre!=-1?dep[pre]+1:0;
    for(i=E[u];i!=-1;i=buf[i].next){
        v = buf[i].b;
        if(v == pre) continue;
        dfs(v,u);
        if(son[u]==-1||num[v]>num[son[u]]) son[u] = v;
        num[u]+=num[v];
    }
}
void buildQTree(int u,int hd){
    int i,v;
    cnt++;
    head[u] = hd;P[u]=cnt;
    if(son[u]!=-1) buildQTree(son[u],hd);
    for(i=E[u];i!=-1;i=buf[i].next){
        v = buf[i].b;
        if(v == son[u] || v == par[u]) continue;
        buildQTree(v,v);
    }
}
int query(int a,int b,int id){
    int ha = head[a],hb = head[b], res = 0;
    while(ha != hb){
        if(ha == -1 || (ha != -1 && hb != -1 && dep[ha] < dep[hb])){
            swap(ha,hb);swap(a,b);
        }
        res += bt.query(P[ha],P[a],id);
        a = par[ha];ha = a != -1 ?head[a] :-1;
    }
    if(a == b) return res + bt.query(P[a],P[a],id);
    if(dep[a] > dep[b]) swap(a,b);
    return res + bt.query(P[a],P[b],id);
}
void DP(int u,int pre){
    int i,v,v1,v2,w,sum = 0;
    dp[u] = 0;
    for(i = E[u];i != -1;i = buf[i].next){
        v = buf[i].b;
        if(v == pre) continue;
        DP(v,u);
        dp[u] += dp[v];
        //bt.add(P[u],dp[v],1);
    }
    bt.add(P[u],dp[u],1);
    sum = dp[u];
//printf("current node %d\n",u);
    for(i = 0;i < G[u].size();i++){
        v1 = G[u][i].u;v2 = G[u][i].v;w = G[u][i].w;
//        dp[u] = max(dp[u],w-sum+query(v1,u,1)-query(v1,u,0)
  //                  +query(v2,u,1)-query(v2,u,0));
//printf("%d %d %d %d\n",query(v1,u,1),query(v1,u,0)
    //                ,query(v2,u,1),query(v2,u,0));
        dp[u] = max(dp[u],w+query(v1,v2,1)-query(v1,v2,0));
//printf("temp : %d %d %d\n",query(v1,v2,1),query(v1,v2,0),w+query(v1,v2,1)-query(v1,v2,0));
//printf("-> %d %d %d %d\n",v1,v2,w,dp[u]);
    }
//printf("answer %d\n",dp[u]);
    bt.add(P[u],dp[u],0);
}


int main(){
    int i,j,cas,u,v,w,op;
    read(cas);
    while(cas--){
        read(n);read(m);
        init();
        for(i = 1;i < n;i++){
            read(u);read(v);u--,v--;
            add_edge(u,v);
        }
        ac.make(0);
        for(i = 0;i < m;i++){
            read(u);read(v);read(w);u--,v--;
            G[ac.ancestor(u,v)].push_back(Chain(u,v,w));
        }
        dfs(0,-1);
        buildQTree(0,0);
        bt.init(cnt);
        DP(0,-1);
        printf("%d\n",dp[0]);
    }

    return 0;
}



  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值