Flash by sshockwave [树dp]
题目
给定一棵树,每个点有一个活动时间,长度为正整数$t_i$
你需要安排每个点的活动时间什么时候开始什么时候结束,并且满足:任何一个时刻没有两个相邻的点都在活动
开始时刻为0,在以上条件下最小化所有点的结束时间之和
$n \leq 2000$
思路
首先,给定的所有$t_i$都是正整数,说明答案一定是整数(这虽然很显然,但是很重要)
考虑某一个点什么时候开始
显然,最优的情况下它的开始时间可以被安排到和自己某个相邻点的结束时间相邻(或者它自己是在开始时刻就开始的)
又考虑到隔壁点也满足这一条,所以对于这个点来说,它的前驱时间(也就是在开始前的等待时间)一定可以被表示为从这个点开始的一条树链的时间和
注意上面的“可以被表示为”这样的表述:不是说只能这么安排,是说这样安排是可行的,而且方便我们设计算法
对于每个点$u$,计算数组$dis[u]$,表示排序去重后的从$u$出发的所有树链的长度
然后设$dp[u][i]$表示从根节点开始$dp$,在当前节点的子树中得到的结果:$dp[u][i]$表示在$u$开始之前已经经过了$dis[u][i]$这么长的等待时间
注意这里的$dp$并没有考虑父亲那边,而是只考虑了子树部分
因此在递归回到父亲那里做转移的时候,要这样操作:
t1[0]=t2[cnt[v]+1]=1e15;
for(i=1;i<=cnt[v];i++) t1[i]=min(t1[i-1],dp[v][i]);
for(i=cnt[v];i>=1;i--) t2[i]=min(t2[i+1],dp[v][i]);
l=0;r=0;
for(i=1;i<=cnt[u];i++){
while(dis[v][l+1]+w[v]<=dis[u][i]) l++;
while(dis[v][r]<dis[u][i]+w[u]) r++;
dp[u][i]+=min(t1[l],t2[r]);
}
做一个前后缀最小值,然后两边双指针进去搞到范围,然后再转移
Code
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cassert>
#define ll long long
using namespace std;
inline int read(){
int re=0,flag=1;char ch=getchar();
while(!isdigit(ch)){
if(ch=='-') flag=-1;
ch=getchar();
}
while(isdigit(ch)) re=(re<<1)+(re<<3)+ch-'0',ch=getchar();
return re*flag;
}
int n,first[10010],cnte=-1;
struct edge{
int to,next;
}a[20010];int w[10010];
inline void add(int u,int v){
a[++cnte]=(edge){v,first[u]};first[u]=cnte;
a[++cnte]=(edge){u,first[v]};first[v]=cnte;
}
ll dis[2010][2010],lis[2010],dp[2010][2010];
int root,cnt[2010];
void getlis(int u,int f,ll d){
lis[++cnt[root]]=d;
// cout<<"getlis "<<u<<' '<<root<<' '<<d<<'\n';
int i,v;
for(i=first[u];~i;i=a[i].next){
v=a[i].to;if(v==f) continue;
getlis(v,u,d+w[v]);
}
}
void init(){
memset(first,-1,sizeof(first));
int i,num,t1,t2;
n=read();
for(i=1;i<n;i++){
t1=read();t2=read();
add(t1,t2);
}
for(i=1;i<=n;i++) w[i]=read();
for(i=1;i<=n;i++){
root=i;getlis(i,0,0);
sort(lis+1,lis+cnt[i]+1);
cnt[i]=unique(lis+1,lis+cnt[i]+1)-lis-1;
memcpy(dis[i]+1,lis+1,sizeof(ll)*(cnt[i]+1));
dis[i][0]=-1e15;
dis[i][cnt[i]+1]=1e15;
}
}
void dfs(int u,int f){
int i,v,j,l,r;
for(i=1;i<=cnt[u];i++) dp[u][i]=dis[u][i]+w[u];
for(i=first[u];~i;i=a[i].next){
v=a[i].to;if(v==f) continue;
dfs(v,u);
}
for(j=first[u];~j;j=a[j].next){
v=a[j].to;if(v==f) continue;
static ll t1[2010],t2[2010];
t1[0]=t2[cnt[v]+1]=1e15;
for(i=1;i<=cnt[v];i++) t1[i]=min(t1[i-1],dp[v][i]);
for(i=cnt[v];i>=1;i--) t2[i]=min(t2[i+1],dp[v][i]);
l=0;r=0;
for(i=1;i<=cnt[u];i++){
while(dis[v][l+1]+w[v]<=dis[u][i]) l++;
while(dis[v][r]<dis[u][i]+w[u]) r++;
dp[u][i]+=min(t1[l],t2[r]);
}
}
}
int main(){
init();
dfs(1,0);
int i;ll ans=1e15;
for(i=1;i<=cnt[1];i++) ans=min(ans,dp[1][i]);
cout<<ans<<'\n';
}
Flash by sshockwave [树dp]的更多相关文章
- CF456D A Lot of Games (字典树+DP)
D - A Lot of Games CF#260 Div2 D题 CF#260 Div1 B题 Codeforces Round #260 CF455B D. A Lot of Games time ...
- HDU4916 Count on the path(树dp??)
这道题的题意其实有点略晦涩,定义f(a,b)为 minimum of vertices not on the path between vertices a and b. 其实它加一个minimum ...
- Codeforces 219D. Choosing Capital for Treeland (树dp)
题目链接:http://codeforces.com/contest/219/problem/D 树dp //#pragma comment(linker, "/STACK:10240000 ...
- HDU4276 The Ghost Blows Light SPFA&&树dp
题目的介绍以及思路完全参考了下面的博客:http://blog.csdn.net/acm_cxlove/article/details/7964739 做这道题主要是为了加强自己对SPFA的代码的训练 ...
- Tsinsen A1219. 采矿(陈许旻) (树链剖分,线段树 + DP)
[题目链接] http://www.tsinsen.com/A1219 [题意] 给定一棵树,a[u][i]代表u结点分配i人的收益,可以随时改变a[u],查询(u,v)代表在u子树的所有节点,在u- ...
- HDU 3016 Man Down (线段树+dp)
HDU 3016 Man Down (线段树+dp) Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Ja ...
- bzoj 3572世界树 虚树+dp
题目大意: 给一棵树,每次给出一些关键点,对于树上每个点,被离它最近的关键点(距离相同被标号最小的)控制 求每个关键点控制多少个点 分析: 虚树+dp dp过程如下: 第一次dp,递归求出每个点子树中 ...
- bzoj 2286 [Sdoi2011]消耗战 虚树+dp
题目大意:多次给出关键点,求切断边使所有关键点与1断开的最小费用 分析:每次造出虚树,dp[i]表示将i和i子树与父亲断开费用 对于父亲x,儿子y ①y为关键点:\(dp[x]\)+=\(dismn( ...
- (纪念第一道完全自己想的树DP)CodeForces 219D Choosing Capital for Treeland
Choosing Capital for Treeland time limit per test 3 seconds memory limit per test 256 megabytes inpu ...
随机推荐
- haystack+Elasticsearch搜素引擎
搜索引擎原理 通过搜索引擎进行数据查询时,搜索引擎并不是直接在数据库中进行查询,而是搜索引擎会对数据库中的数据进行一遍预处理,单独建立起一份索引结构数据. 我们可以将索引结构数据想象成是字典书籍的索引 ...
- centos编译安装rabbitmq
安装环境 [root@VM_12_50_centos rabbitmq]# uname -a Linux VM_12_50_centos 3.10.0-514.21.1.el7.x86_64 #1 S ...
- 爬虫之requests模块基础
一.request模块介绍 1. 什么是request模块 - python中原生的基于网络请求的模块,模拟浏览器发起请求. 2. 为什么使用request模块 - urllib需要手动处理url编码 ...
- 第一次学习tornado小练习
内容 这次是python的一个web框架,tornado,这个web框架在python的几个web框架中一个比较简单的web框架,刚开始接触python的时候就知道python有两个比较常用的web框 ...
- linux基础重要命令小节
此为L005&&L006课程内容的一个总结. 命令: 基本形式 命令 [参数] [路径或文件] 例:ls -ld /data pwd 目前所在目录 [root@moban /]# pw ...
- SharePoint2013修复报错
今天项目组的Sharepoint2013不小心被卸载了,本想着直接修复,谁知道在修复的时候一直报错,说找不到什么文件.报的就是类似于这样的错误: Product: ######### -- ...
- Python连接符的种类和使用区别
python的连接符主要有 加号(+).逗号(,).空格( ) .反斜线(\).join()的方式. 加号(+),demo如下: #注意,+只能连接字符串,如果一个是字符串一个是数字就会报错 pr ...
- 云计算之路-阿里云上:原来“黑色0.1秒”发生在socket读取数据时
在昨天的博文(云计算之路-阿里云上:读取缓存时的“黑色0.1秒”)中我们犯了一个很低级的错误——把13ms算成了130ms(感谢陈硕发现这个错误!),从而对问题的原因作出了错误的推断,望大家谅解! 从 ...
- 使用polarssl进行RSA加密解密
RSA算法的原理就不提了,网上有很多介绍的文章,因为项目中使用RSA加密,所以需要找一个RSA加密的算法,之前尝试过使用Crypto++库,无奈Crypto++其中使用了大量的模版,各种继承,看着头大 ...
- svn 用cmd命令行启动服务
部署好svn 服务器后,用cmd命令行 svnserve -d -r [仓库地址] 启动服务,这样别的用户可以通过网络访问svn服务器了.