HDU 5815 Golden Week

给定一个n个点的有根树。有m个旅客,第i个旅客打算从1走到Bi,预算为Ci,如果花费大于预算就会放弃前往。要求给每条边设一个过路费,最大化收益(SPJ)。

比赛的时候bblss123想出来了,但因为我们的失误怠慢了它==,然后它就睡觉去了,不然真能抢到First Blood==。

dp[i][j] :1(根节点)到i的花费为j为hash[j]时i的子树中最大收益

dp[i][j]=hash[j](i,>=hash[j])+sson(i)max(dp[s][k],kj) .

然后单调处理一下就好了,难怪大家都懒得写==

树形dp

#include <set>
#include <ctime>
#include <queue>
#include <cstdio>
#include <bitset>
#include <cctype>
#include <bitset>
#include <cstdlib>
#include <cassert>
#include <cstring>
#include <iostream>
#include <algorithm>
#define inf (1<<30)
#define INF (1ll<<62)
#define fi first
#define se second
#define rep(x,s,t) for(register int x=s,t_=t;x<t_;++x)
#define per(x,s,t) for(register int x=t-1,s_=s;x>=s_;--x)
#define prt(x) cout<<#x<<":"<<x<<" "
#define prtn(x) cout<<#x<<":"<<x<<endl
#define travel(x) for(int I=last[x],to;(~I)&&(to=e[I].to);I=e[I].nxt)
#define pb(x) push_back(x)
#define hash asfmaljkg
#define rank asfjhgskjf
#define y1 asggnja
#define y2 slfvm
using namespace std;
typedef long long ll;
typedef pair<int,int> ii;
template<class T>void sc(T &x){
    int f=1;char c;x=0;
    while(c=getchar(),c<48)if(c=='-')f=-1;
    do x=x*10+(c^48);
    while(c=getchar(),c>47);
    x*=f;
}
template<class T>void nt(T x){
    if(!x)return;
    nt(x/10);
    putchar(x%10+'0');
}
template<class T>void pt(T x){
    if(x<0)putchar('-'),x=-x;
    if(!x)putchar('0');
    else nt(x);
}
template<class T>void ptn(T x){
    pt(x);putchar('\n');
}
template<class T>void pts(T x){
    pt(x);putchar(' ');
}
template<class T>inline void Max(T &x,T y){if(x<y)x=y;}
template<class T>inline void Min(T &x,T y){if(x>y)x=y;}

int n,m;
const int maxn=1005;
int has[maxn],tot;

int last[maxn],ecnt;
struct Edge{
    int to,nxt;
}e[maxn<<1];
int val[maxn];

void ins(int u,int v){
    e[ecnt]=(Edge){v,last[u]};
    last[u]=ecnt++;
}

int sz[maxn],bag[maxn][maxn];
int tar[maxn],hav[maxn];

ll dp[maxn][maxn];
//dp[i][j]:1到i的代价为has[j]时的最大收益 

void dfs(int x,int f){
    travel(x)if(to^f)dfs(to,x);
    int top=sz[x];
    per(i,0,tot+1){
        while(top&&bag[x][top-1]>=i)top--;
        dp[x][i]=1ll*has[i]*(sz[x]-top);
        travel(x)if(to^f)
            dp[x][i]+=dp[to][i];
        if(i<tot)Max(dp[x][i],dp[x][i+1]);
    }
}

void rdfs(int x,int cost,int f){
    travel(x)if(to^f){
        int j;
        for(j=cost;j<=tot&&dp[to][j]==dp[to][cost];j++);
        --j;
        val[I>>1]=has[j]-has[cost];
        rdfs(to,j,x);
    }
}

void solve(){
    sc(n);sc(m);
    memset(last,-1,n+1<<2);
    ecnt=0;

    rep(i,1,n){
        int u,v;
        sc(u);sc(v);
        ins(u,v);
        ins(v,u);
    }

    tot=0;
    rep(i,1,m+1){
        sc(tar[i]),sc(hav[i]);
        if(tar[i]==1)hav[i]=0;
        has[++tot]=hav[i];
    }

    sort(has+1,has+tot+1);
    tot=unique(has+1,has+tot+1)-has-1;

    memset(sz,0,n+1<<2);
    rep(i,1,m+1){
        hav[i]=lower_bound(has+1,has+tot+1,hav[i])-has;
        bag[tar[i]][sz[tar[i]]++]=hav[i];
    }
    rep(i,1,n+1)sort(bag[i],bag[i]+sz[i]);

    dfs(1,0);
    ptn(dp[1][0]);
    rdfs(1,0,0);

    rep(i,0,n-2)pts(val[i]);
    ptn(val[n-2]);
}

int main(){
//  freopen("pro.in","r",stdin);
//  freopen("chk.out","w",stdout);
    int cas;sc(cas);
    while(cas--)solve();    
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值