Hihocoder 1035 [树形dp]

/*
题意:
不要低头,不要放弃,不要气馁,不要慌张。
PS:人生第一道自己独立做出来的树形dp...
给一棵树,标号1到n,每条边有两个权值,步行时间和驾车时间。车在1号点。
给m个必须访问的关键点,求从1号点出发,访问所有关键点一遍的最小时间。
注意车可以停在任意地方,但是只有1号点有一辆车,人最后也可以停留在任意点。
思路:
1.子树方向(注意dp1 dp2 dp4都是保证人一定要返回该点的最优解)
dp1代表该点起始有车,并且从该点出发访问完该点子树上所有的关键点车和人都返回的该点的最优解。
注意dp1并不是访问每个子树都要驾车,只要保证该子树访问完人和车都在该点就可以,也就是也可以步行出发并返回。
dp2代表该点起始有车,从该点出发人必须返回,但是车不一定返回的最优解。
dp4代表该点起始无车,从该点出发步行并且返回该点的最优解。
2.父亲节点方向
显而易见,最后人一定会停留在某点。
dp1代表该点起始有车(从父亲方向来的车),并且访问完所有关键节点最后车和人都返回该点的最优解。
d2维护的是该点起始有车(从父亲方向来的车),访问完所有关键节点人返回,车不一定返回的最优解和次优解。并且记录最后车不返回的子树。
dp4代表该点起始无车(从父亲方向无车来),步行访问完所有关键节点的最优解。
总之最后总的思想就是,枚举最后人停留的点,不断找ans的最小值。

好像跟网上聚聚们写的思路不太一样...

坑:
sum=min(sum,sum-it->w+it->c-dp1[it->id]+dp2[it->id]);
*/

#include<bits/stdc++.h>
#define N 1000050
using namespace std;
long long ans;
struct st{
    st(){}
    st(int a,long long b){
        id=a;val=b;
    }
    int id;
    long long val;
};
bool cmp(st a,st b){
    if(a.val!=b.val)return a.val<b.val;
    return a.id<b.id;
}
vector<st>mv;
st d2[N][2];
long long inf=0x3f3f3f3f3f3f3f3f;
struct edge{
    int id;
    long long w,c;
    edge *next;
};
int ednum;
edge edges[N<<1];
edge *adj[N];
inline void addedge(int a,int b,long long c,long long w){
    edge *tmp=&edges[ednum++];
    tmp->id=b;
    tmp->w=w;
    tmp->c=c;
    tmp->next=adj[a];
    adj[a]=tmp;
}
int im[N],fa[N],siz[N];
long long dp1[N],dp2[N],dp4[N];
void dfs(int pos){
    siz[pos]=im[pos];
    for(edge *it=adj[pos];it;it=it->next){
        if(!fa[it->id]){
            fa[it->id]=pos;
            dfs(it->id);
            siz[pos]+=siz[it->id];
        }
    }
    if(siz[pos]==1&&im[pos]){
        dp1[pos]=dp2[pos]=dp4[pos]=0;
    }
    else if(siz[pos]){
        long long sum=0,sum1=0;
        for(edge *it=adj[pos];it;it=it->next){
            if(fa[it->id]!=pos)continue;
            if(siz[it->id]){
                sum+=min(dp1[it->id]+2*it->w,dp4[it->id]+2*it->c);
                sum1+=dp4[it->id]+2*it->c;
            }
        }
        dp1[pos]=sum;
        dp4[pos]=sum1;
        long long aaa=sum;
        for(edge *it=adj[pos];it;it=it->next){
            if(fa[it->id]!=pos)continue;
            if(siz[it->id]){
                if(dp1[it->id]+2*it->w < dp4[it->id]+2*it->c)
                    aaa=min(aaa,min(sum - it->w + it->c , sum - it->w - dp1[it->id] + dp2[it->id] + it->c));
                else
                    aaa=min(aaa,min(sum - it->c - dp4[it->id] + it->w + dp1[it->id],sum - it->c - dp4[it->id] + it->w +dp2[it->id]));
            }
        }
        dp2[pos]=aaa;
    }
}
void dfs2(int pos,long long ww,long long cc){
    mv.clear();
    if(pos==1){
        ans=min(ans,dp1[pos]);
        long long sum=dp1[pos];
        for(edge *it=adj[pos];it;it=it->next){
            sum=dp1[pos];
            if(fa[it->id]==pos&&siz[it->id]){
                if(dp1[it->id] + 2 * it->w < dp4[it->id] + 2*it->c )
                    sum=min(sum,dp1[pos] - it->w + it->c - dp1[it->id] + dp2[it->id] );
                else
                    sum=min(sum,dp1[pos]-it->c+it->w-dp4[it->id]+dp2[it->id]);
                mv.push_back(st(it->id,sum));
            }
        }
        mv.push_back(st(0,dp1[pos]));
        mv.push_back(st(0,dp1[pos]));
        sort(mv.begin(),mv.end(),cmp);
        d2[pos][0]=mv[0];
        d2[pos][1]=mv[1];
        ans=min(ans,d2[pos][0].val);
        ans=min(ans,dp4[pos]);
    }
    else{
        long long ss=dp1[fa[pos]];
        if(dp1[pos]+2*ww<dp4[pos]+2*cc)ss-=dp1[pos]+2*ww;
        else ss-=dp4[pos]+2*cc;
        ss+=cc;
        if(d2[fa[pos]][0].id!=pos){
            long long sss=d2[fa[pos]][0].val;
            if(dp1[pos]+2*ww<dp4[pos]+2*cc)sss-=dp1[pos]+2*ww;
            else sss-=dp4[pos]+2*cc;
            sss+=cc;
            ss=min(ss,sss);
        }
        else{
            long long sss=d2[fa[pos]][1].val;
            if(dp1[pos]+2*ww<dp4[pos]+2*cc)sss-=dp1[pos]+2*ww;
            else sss-=dp4[pos]+2*cc;
            sss+=cc;
            ss=min(ss,sss);
        }
        ss=min(ss,dp4[fa[pos]]-cc-dp4[pos]);
        long long bb=dp1[fa[pos]];
        if(dp1[pos]+2*ww<dp4[pos]+2*cc)bb-=dp1[pos]+2*ww;
        else bb-=dp4[pos]+2*cc;
        bb+=ww;
        dp1[pos]=bb;
        for(edge *it=adj[pos];it;it=it->next){
            if(fa[it->id]==pos&&siz[it->id]){
                dp1[pos]+=min(dp1[it->id]+2*it->w,dp4[it->id]+2*it->c);
            }
        }
        ans=min(ans,dp1[pos]);
        long long sum=dp1[pos];
        for(edge *it=adj[pos];it;it=it->next){
            sum=dp1[pos];
            if(fa[it->id]==pos&&siz[it->id]){
                if(dp1[it->id]+2*it->w<dp4[it->id]+2*it->c)
                    sum=min(sum,dp1[pos]-it->w+it->c-dp1[it->id]+dp2[it->id]);
                else
                    sum=min(sum,dp1[pos]-it->c+it->w-dp4[it->id]+dp2[it->id]);
                mv.push_back(st(it->id,sum));
            }
        }
        mv.push_back(st(0,dp1[pos]));
        mv.push_back(st(0,dp1[pos]));
        sort(mv.begin(),mv.end(),cmp);
        d2[pos][0]=mv[0];
        d2[pos][1]=mv[1];
        dp4[pos]+=ss;
        ans=min(ans,dp4[pos]);
        ans=min(ans,d2[pos][0].val);
    }
    for(edge *it=adj[pos];it;it=it->next){
        if(fa[it->id]==pos&&siz[it->id]){
            dfs2(it->id,it->w,it->c);
        }
    }
}
int main()
{
    fa[1]=-1;
    int n;
    scanf("%d",&n);
    int a,b;
    long long w,c;
    for(int i=1;i<=n;i++){
        dp1[i]=dp2[i]=dp4[i]=inf;
    }
    for(int i=1;i<n;i++){
        scanf("%d%d%lld%lld",&a,&b,&c,&w);
        addedge(a,b,c,w);
        addedge(b,a,c,w);
    }
    int m;
    scanf("%d",&m);
    for(int i=1;i<=m;i++){
        scanf("%d",&a);
        im[a]=1;
    }
    dfs(1);
    ans=inf;
    dfs2(1,0,0);
    printf("%lld\n",ans);
}
时间: 2024-11-03 03:27:55

Hihocoder 1035 [树形dp]的相关文章

树形DP新识

HihoCoder: 1041(点) 1063(边) 1035(边) 目前我遇到的树形DP有两类: ?:点处理,大概就是点的乱搞,比如找一些点,这些点权值和最大.dp[node][m],表示给node为节点的子树分配m个点的最优结果 ?:边处理,路径问题,由于'一笔画'或者其他要求,要求一条边一条边的走,需要加一维表示是否回到起点.dp[node][m][state],state表示是否回来等等.

HDU-2196 Computer (树形DP)

最近在看树形DP,这题应该是树形DP的经典题了,写完以后还是有点感觉的.之后看了discuss可以用树分治来做,以后再试一试. 题目大意 找到带权树上离每个点的最远点.︿( ̄︶ ̄)︿ 题解: 对于每一个点的最远点,就是以这个点为根到所有叶子节点的最长距离.但是如果确定根的话,除了根节点外,只能找到每个节点(度数-1)个子树的最大值,剩下一个子树是该节点当前的父亲节点. 所以当前节点的最远点在当前节点子树的所有叶子节点以及父亲节点的最远点上(当父亲节点的最远点不在当前节点的子树上时), 如果父亲节

UVA-01220 Party at Hali-Bula (树形DP+map)

题目链接:https://vjudge.net/problem/UVA-1220 思路: 树形DP模板题,求最大人数很简单,难点在于如何判断最大人数的名单是否有不同的情况: 解决方法是用一个数组f[manx][2]记录该节点是否出场的情况,为真时代表有多种情况; 具体讨论: 当父节点的值加上某个子节点的值时,他的f的情况也和该子节点一样: 当某个节点dp(i, 0) == dp(i, 1), 则该节点以及它的父节点也一定有多种情况(父节点必定取其中之一). Code: 1 #include<bi

HDU 1520 树形dp裸题

1.HDU 1520  Anniversary party 2.总结:第一道树形dp,有点纠结 题意:公司聚会,员工与直接上司不能同时来,求最大权值和 #include<iostream> #include<cstring> #include<cmath> #include<queue> #include<algorithm> #include<cstdio> #define max(a,b) a>b?a:b using nam

HDU2196 Computer(树形DP)

和LightOJ1257一样,之前我用了树分治写了.其实原来这题是道经典的树形DP,感觉这个DP不简单.. dp[0][u]表示以u为根的子树中的结点与u的最远距离 dp[1][u]表示以u为根的子树中的结点与u的次远距离 这两个可以一遍dfs通过儿子结点转移得到.显然dp[0][u]就是u的一个可能的答案,即u往下走的最远距离,还缺一部分就是u往上走的最远距离: dp[2][u]表示u往上走的最远距离 对于这个的转移,分两种情况,是这样的: dp[2][v] = max( dp[0][u]+w

hdu5593--ZYB&#39;s Tree(树形dp)

问题描述 ZYB有一颗N个节点的树,现在他希望你对于每一个点,求出离每个点距离不超过KK的点的个数. 两个点(x,y)在树上的距离定义为两个点树上最短路径经过的边数, 为了节约读入和输出的时间,我们采用如下方式进行读入输出: 读入:读入两个数A,B,令fai??为节点i的父亲,fa?1??=0;fa?i??=(A∗i+B)%(i−1)+1,i∈[2,N] . 输出:输出时只需输出N个点的答案的xor和即可. 输入描述 第一行一个整数TT表示数据组数. 接下来每组数据: 一行四个正整数N,K,A,

CF 219D Choosing Capital for Treeland 树形DP 好题

一个国家,有n座城市,编号为1~n,有n-1条有向边 如果不考虑边的有向性,这n个城市刚好构成一棵树 现在国王要在这n个城市中选择一个作为首都 要求:从首都可以到达这个国家的任何一个城市(边是有向的) 所以一个城市作为首都,可能会有若干边需要改变方向 现在问,选择哪些城市作为首都,需要改变方向的边最少. 输出最少需要改变方向的边数 输出可以作为首都的编号 树形DP 先假定城市1作为首都 令tree(i)表示以i为根的子树 dp[i]表示在tree(i)中,若以i为首都的话,需要改变的边数 第一次

HDU 1011 Starship Troopers(树形dp+背包)

Starship Troopers Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 13109    Accepted Submission(s): 3562 Problem Description You, the leader of Starship Troopers, are sent to destroy a base of

Codeforces 462D Appleman and Tree 树形dp

题目链接:点击打开链接 题意: 给定n个点的树, 0为根,下面n-1行表示每个点的父节点 最后一行n个数 表示每个点的颜色,0为白色,1为黑色. 把树分成若干个联通块使得每个联通块有且仅有一个黑点,问有多少种分法(结果mod1e9+7) 思路: 树形dp,每个点有2个状态,已经归属于某个黑点和未归属于某个黑点. #include <cstdio> #include <vector> #include <iostream> using namespace std; #de