/*
题意:
不要低头,不要放弃,不要气馁,不要慌张。
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][];
long long inf=0x3f3f3f3f3f3f3f3f;
struct edge{
int id;
long long w,c;
edge *next;
};
int ednum;
edge edges[N<<];
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]==&&im[pos]){
dp1[pos]=dp2[pos]=dp4[pos]=;
}
else if(siz[pos]){
long long sum=,sum1=;
for(edge *it=adj[pos];it;it=it->next){
if(fa[it->id]!=pos)continue;
if(siz[it->id]){
sum+=min(dp1[it->id]+*it->w,dp4[it->id]+*it->c);
sum1+=dp4[it->id]+*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]+*it->w < dp4[it->id]+*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==){
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] + * it->w < dp4[it->id] + *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(,dp1[pos]));
mv.push_back(st(,dp1[pos]));
sort(mv.begin(),mv.end(),cmp);
d2[pos][]=mv[];
d2[pos][]=mv[];
ans=min(ans,d2[pos][].val);
ans=min(ans,dp4[pos]);
}
else{
long long ss=dp1[fa[pos]];
if(dp1[pos]+*ww<dp4[pos]+*cc)ss-=dp1[pos]+*ww;
else ss-=dp4[pos]+*cc;
ss+=cc;
if(d2[fa[pos]][].id!=pos){
long long sss=d2[fa[pos]][].val;
if(dp1[pos]+*ww<dp4[pos]+*cc)sss-=dp1[pos]+*ww;
else sss-=dp4[pos]+*cc;
sss+=cc;
ss=min(ss,sss);
}
else{
long long sss=d2[fa[pos]][].val;
if(dp1[pos]+*ww<dp4[pos]+*cc)sss-=dp1[pos]+*ww;
else sss-=dp4[pos]+*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]+*ww<dp4[pos]+*cc)bb-=dp1[pos]+*ww;
else bb-=dp4[pos]+*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]+*it->w,dp4[it->id]+*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]+*it->w<dp4[it->id]+*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(,dp1[pos]));
mv.push_back(st(,dp1[pos]));
sort(mv.begin(),mv.end(),cmp);
d2[pos][]=mv[];
d2[pos][]=mv[];
dp4[pos]+=ss;
ans=min(ans,dp4[pos]);
ans=min(ans,d2[pos][].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[]=-;
int n;
scanf("%d",&n);
int a,b;
long long w,c;
for(int i=;i<=n;i++){
dp1[i]=dp2[i]=dp4[i]=inf;
}
for(int i=;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=;i<=m;i++){
scanf("%d",&a);
im[a]=;
}
dfs();
ans=inf;
dfs2(,,);
printf("%lld\n",ans);
}

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

  1. HihoCoder - 1055 树形dp

    vj链接:https://vjudge.net/contest/367007#problem/G 题意: 给你一棵树,树上有n个节点,每一个节点有一个权值,树根节点是1,你需要找到以1为起点连通的m个 ...

  2. hihocoder 1515 分数调查(树形dp)

    hihocoder 1515 分数调查 时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 小Hi的学校总共有N名学生,编号1-N.学校刚刚进行了一场全校的古诗文水平测验. ...

  3. hihocoder 1676 树上等差数列 黑科技树形dp

    #1676 : 树上的等差数列 时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 给定一棵包含N个节点的无根树,节点编号1~N.其中每个节点都具有一个权值,第i个节点的权值 ...

  4. 树形DP新识

    HihoCoder: 1041(点) 1063(边) 1035(边) HDU1520 (签到) HDU2415(emm) 目前我遇到的树形DP有两类: ∂:点处理,大概就是点的乱搞,比如找一些点,这些 ...

  5. 算法笔记--树的直径 && 树形dp && 虚树 && 树分治 && 树上差分 && 树链剖分

    树的直径: 利用了树的直径的一个性质:距某个点最远的叶子节点一定是树的某一条直径的端点. 先从任意一顶点a出发,bfs找到离它最远的一个叶子顶点b,然后再从b出发bfs找到离b最远的顶点c,那么b和c ...

  6. 树形DP专题

    DP是我的弱项, 此专题意在总结树形DP的解题思路. 最小代价遍历一棵树 给定一棵带边权的树 $T=(V,E)$ , 遍历它 (树的每个节点都访问至少一次) 所需的最小代价. 这里的代价由具体问题所定 ...

  7. poj3417 LCA + 树形dp

    Network Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 4478   Accepted: 1292 Descripti ...

  8. COGS 2532. [HZOI 2016]树之美 树形dp

    可以发现这道题的数据范围有些奇怪,为毛n辣么大,而k只有10 我们从树形dp的角度来考虑这个问题. 如果我们设f[x][k]表示与x距离为k的点的数量,那么我们可以O(1)回答一个询问 可是这样的话d ...

  9. 【BZOJ-4726】Sabota? 树形DP

    4726: [POI2017]Sabota? Time Limit: 20 Sec  Memory Limit: 128 MBSec  Special JudgeSubmit: 128  Solved ...

随机推荐

  1. iOS开发拓展篇—音频处理(音乐播放器2)

    iOS开发拓展篇—音频处理(音乐播放器2) 说明:该文主要介绍音乐播放界面的搭建. 一.跳转 1.跳转到音乐播放界面的方法选择 (1)使用模态跳转(又分为手动的和自动的) (2)使用xib并设置跳转 ...

  2. iOS开发UI篇—popoverController简单介绍

    iOS开发UI篇—popoverController简单介绍 一.简单介绍 1.什么是UIPopoverController 是iPad开发中常见的一种控制器(在iPhone上不允许使用) 跟其他控制 ...

  3. net 的单元测试 初学

    1. 都要以一个方法 这样的去测试 2. 利用工具 Install-Package Moq -Version 4.0 (最高的是4.5  4.0适用于自己项目的版本)   Moq.dll 进行测试   ...

  4. 解决Only a type can be imported. com.mysql.jdbc.Connection resolves to a package的报错问题

    写jsp加载数据驱动以后老是提示Only a type can be imported. com.mysql.jdbc.Connection resolves to a package的错误,然而改成 ...

  5. 黑马程序员——【Java基础】——网络编程

    ---------- android培训.java培训.期待与您交流! ---------- 一.网络模型概述 网络模型示意图: 说明: (1)数据的传输:在用户端,应用层的数据,经过层层封包,最后到 ...

  6. HDU5127 神坑题---vector 、 list 、 deque 的用法区别

    题意:三个操作 1  a b : 队列中加入(x = a, y = b); -1  a b : 队列中减去(x = a, y = b); 0  p q :从队列的数对中查询哪一对x,y能够让 p * ...

  7. PCL安装使用

    一. 下载安装 http://pointclouds.org/downloads/windows.html 1. QT安装在默认路径下(否则后续会出现问题),添加环境变量QTDIR(c:\Qt\4.8 ...

  8. PHP数组操作汇总 php数组的使用技巧

    对于Web编程来说,最重要的就是存取和读写数据了.存储方式可能有很多种,可以是字符串.数组.文件的形式等.   数组,可以说是PHP的数据应用中较重要的一种方式.PHP的数组函数众多,下面是我学习的小 ...

  9. Linux文件操作 笔记

    fstat stat lstat 原型 #include <unistd.h> #include <sys/stat.h> #include <sys/types.h&g ...

  10. For xml path

    Select * from tb for xml path('') 特点: 1. 以xml形式展示查询数据. 2. 自定义数据展示类型. 实例: 1. Select * from tb for xml ...