POJ 3162 Walking Race 树形DP+线段树
给出一棵树,编号为1~n,给出数m
漂亮mm连续n天锻炼身体,每天会以节点i为起点,走到离i最远距离的节点
走了n天之后,mm想到知道自己这n天的锻炼效果
于是mm把这n天每一天走的距离记录在一起,成为一段长度为n的数列
现在mm想要从这数列中选出一个连续的区间,要求这个区间的max-min<=m
输出最长的区间
做了一个下午
思路:
分成2个部分:
1.求出数列,即对于一棵树,求出每一个节点能到达的最远距离
2.对于这段数列,选出一个区间,使得区间的max-min<=m,并且使得区间长度尽量长。
对于第1部分,其实就是我昨天做的题目,HDU2196,使用树形DP
dp[i][1]:表示从i出发到i的子树,能到达的最远距离
dp[i][2]:表示从i出发到i的子树,能到达的第二远的距离(求dp[i][0]的时候需要用到)
dp[i][0]:表示从i出发,经过i的父亲节点,能到达的最远距离
4次dfs,分别求出:
0.节点的depth,以便把边权(u,v)转化为u,v中depth较大的节点的点权,cost[root]=0;
1.求出dp[i][1]和son[i],son[i]表示dp[i][1]是通过子节点son[i]这道路径得到的
2.求出dp[i][2]
3.求出dp[i][0]
完成第一部分
第二部分,前段时间也做过类似的题,HDU5289
5289要求的是数列中有多少个区间满足条件,我是用RMQ+二分
这道求的是满足条件的最长区间长度
我主要时间是花在了解决第二部分
我刚开始也是用RMQ+二分
发现mle了
因为5289的长度n<=1e5,而这道,n<=1e6,所以RMQ开了会mle
然后我就想改为用线段树代替RMQ的作用,用线段树维护区间的最大值和最小值也很方便,还可以省下很多空间
然后,tle了
原因:
这道题和5289不同的是,这道题不用枚举每一个区间,判断到底满不满足要求
只要求出一个满足的最长的就好啦
然后把枚举左端点+二分右端点的代码注释了
换了种方式:
用2个指针l,r,
若区间[l,r]满足条件,r++,同时更新答案
若不满足条件,l++,直到[l,r]满足条件
复杂度O(n)
这就是传说中的尺取法?
这过程我还犯了一个及其严重的错误:
求最大值的时候,没有把max_ret初始化为-inf
求最小值的时候,没有把min_ret初始化为inf
又花了不少时间
然后终于过了
#include<cstdio>
#include<cstring> using namespace std;
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1 inline int max(int a,int b)
{
return a>b?a:b;
} inline int min(int a,int b)
{
return a<b?a:b;
} const int maxn=1e6+;
const int inf=0x3f3f3f3f; struct Edge
{
int to,next;
};
Edge edge[maxn<<];
int head[maxn];
int tot;
int son[maxn];
int dp[maxn][];
int e[maxn][];
int dep[maxn];
int cost[maxn];
int seg_max[maxn<<];
int seg_min[maxn<<];
int max_ret;
int min_ret; void init()
{
memset(head,-,sizeof head);
tot=;
memset(dep,,sizeof dep);
memset(dp,,sizeof dp);
memset(son,-,sizeof son);
} void addedge(int u,int v)
{
edge[tot].to=v;
edge[tot].next=head[u];
head[u]=tot++;
} void solve(int n,int m);
void dfs0(int u,int pre);
void dfs1(int u,int pre);
void dfs2(int u,int pre);
void dfs3(int u,int pre);
void build(int l,int r,int rt);
void pushup(int rt);
int query(int L,int R,int n);
void query_ret(int L,int R,int l,int r,int rt); int main()
{
int n,m;
while(~scanf("%d %d",&n,&m))
{
init();
for(int i=;i<=n;i++)
{
int u,v;
scanf("%d %d",&e[i][],&e[i][]);
addedge(i,e[i][]);
addedge(e[i][],i);
}
solve(n,m);
}
return ;
} void solve(int n,int m)
{
dfs0(,-);
cost[]=;
for(int i=;i<=n;i++)
{
if(dep[i]>dep[e[i][]])
cost[i]=e[i][];
else
cost[e[i][]]=e[i][];
}
dfs1(,-);
dfs2(,-);
dfs3(,-);
build(,n,);
/*
for(int i=1;i<=n;i++)
{
printf("%d\n",max(dp[i][0],dp[i][1]));
}
*/
/*
int ans=0;
for(int i=1;i<=n;i++)
{
int l=i,r=n;
while(r-l>1)
{
int mid=(l+r)>>1;
if(query(i,mid,n)>m)
r=mid;
else
l=mid;
}
if(query(i,r,n)<=m)
ans=max(ans,r-i+1);
else
ans=max(ans,l-i+1);
}
*/ int ans=;
int l=,r=;
while(r<=n)
{
while(l<=r&&query(l,r,n)>m)
{
l++;
}
while(r<=n&&query(l,r,n)<=m)
{
ans=max(ans,r-l+);
r++;
}
} printf("%d\n",ans);
return ;
} void dfs0(int u,int pre)
{
for(int i=head[u];~i;i=edge[i].next)
{
int v=edge[i].to;
if(v==pre)
continue;
dep[v]=dep[u]+;
dfs0(v,u);
}
} void dfs1(int u,int pre)
{
for(int i=head[u];~i;i=edge[i].next)
{
int v=edge[i].to;
if(v==pre)
continue;
dfs1(v,u);
if(dp[v][]+cost[v]>dp[u][])
{
dp[u][]=dp[v][]+cost[v];
son[u]=v;
}
}
} void dfs2(int u,int pre)
{
for(int i=head[u];~i;i=edge[i].next)
{
int v=edge[i].to;
if(v==pre)
continue;
dfs2(v,u);
if(v==son[u])
continue;
if(dp[v][]+cost[v]>dp[u][])
{
dp[u][]=dp[v][]+cost[v];
}
}
} void dfs3(int u,int pre)
{
for(int i=head[u];~i;i=edge[i].next)
{
int v=edge[i].to;
if(v==pre)
continue;
if(v==son[u])
{
dp[v][]=max(dp[u][],dp[u][])+cost[v];
}
else
{
dp[v][]=max(dp[u][],dp[u][])+cost[v];
}
dfs3(v,u);
}
} void pushup(int rt)
{
seg_max[rt]=max(seg_max[rt<<],seg_max[rt<<|]);
seg_min[rt]=min(seg_min[rt<<],seg_min[rt<<|]);
} void build(int l,int r,int rt)
{
if(l==r)
{
seg_max[rt]=seg_min[rt]=max(dp[l][],dp[l][]);
return ;
}
int m=(l+r)>>;
build(lson);
build(rson);
pushup(rt);
} int query(int L,int R,int n)
{
max_ret=-inf;
min_ret=inf;
query_ret(L,R,,n,);
return max_ret-min_ret;
} void query_ret(int L,int R,int l,int r,int rt)
{
if(L<=l&&R>=r)
{
max_ret=max(max_ret,seg_max[rt]);
min_ret=min(min_ret,seg_min[rt]);
return ;
}
int m=(l+r)>>;
if(L<=m)
query_ret(L,R,lson);
if(R>m)
query_ret(L,R,rson);
}
POJ 3162 Walking Race 树形DP+线段树的更多相关文章
- POJ 3162.Walking Race 树形dp 树的直径
Walking Race Time Limit: 10000MS Memory Limit: 131072K Total Submissions: 4123 Accepted: 1029 Ca ...
- POJ - 3162 Walking Race 树形dp 单调队列
POJ - 3162Walking Race 题目大意:有n个训练点,第i天就选择第i个训练点为起点跑到最远距离的点,然后连续的几天里如果最远距离的最大值和最小值的差距不超过m就可以作为观测区间,问这 ...
- 【题解】poj 3162 Walking Race 树形dp
题目描述 Walking RaceTime Limit: 10000MS Memory Limit: 131072KTotal Submissions: 4941 Accepted: 1252Case ...
- POJ 3162 Walking Race 树形dp 优先队列
http://poj.org/problem?id=3162 题意 : 一棵n个节点的树.wc爱跑步,跑n天,第i天从第i个节点开始跑步,每次跑到距第i个节点最远的那个节点(产生了n个距离),现在要 ...
- POJ 3162 Walking Race(树形dp+单调队列 or 线段树)
http://poj.org/problem?id=3162 题意:一棵n个节点的树.有一个屌丝爱跑步,跑n天,第i天从第i个节点开始跑步,每次跑到距第i个节点最远的那个节点(产生了n个距离),现在要 ...
- Codeforces 671D. Roads in Yusland(树形DP+线段树)
调了半天居然还能是线段树写错了,药丸 这题大概是类似一个树形DP的东西.设$dp[i]$为修完i这棵子树的最小代价,假设当前点为$x$,但是转移的时候我们不知道子节点到底有没有一条越过$x$的路.如果 ...
- hdu5293 Tree chain problem 树形dp+线段树
题目:pid=5293">http://acm.hdu.edu.cn/showproblem.php?pid=5293 在一棵树中,给出若干条链和链的权值.求选取不相交的链使得权值和最 ...
- poj3162(树形dp+线段树求最大最小值)
题目链接:https://vjudge.net/problem/POJ-3162 题意:给一棵树,求每个结点的树上最远距离,记为a[i],然后求最大区间[l,r]满足区间内的max(a[i])-min ...
- Codeforces Round #530 (Div. 2) F (树形dp+线段树)
F. Cookies 链接:http://codeforces.com/contest/1099/problem/F 题意: 给你一棵树,树上有n个节点,每个节点上有ai块饼干,在这个节点上的每块饼干 ...
随机推荐
- PHP 页面自动刷新可借助JS来实现,简单示例如下:
<?php echo "系统当前时间戳为:"; echo ""; echo time(); //<!--JS 页面自动刷新 --> echo ...
- poj2762 强连通+拓扑序
题意:有 n 个房间,不同房间之间有单向通道,问是否任意两个房间 A .B 都可以从 A 到 B 或从 B 到 A(有一条有就可以). 在这题中,如果一些点是在同一个强连通分量中,那么这些点肯定能够相 ...
- 渴切-开源中文css框架
渴切:是国内优秀的开源css框架. 渴切是一个开源中文 (X)HTML/CSS 框架 ,它的目的是减少你的css开发时间.它提供一个可靠的css基础去创建你的项目,能够用于网站的快速设计,通过重设和重 ...
- Windows下IntelliJ IDEA中运行Spark Standalone
ZHUAN http://www.cnblogs.com/one--way/archive/2016/08/29/5818989.html http://www.cnblogs.com/one--wa ...
- createdb test时报global/pg_filenode.map不存在
实际上是存在的,看到说是ipv6占用了5432的端口号,看了一下的确是,将ipv6关闭重启系统即可. 下面是关闭ipv6的方法: 确认IPV6是否开启 在Linux下确认IPv6是否已经被启用,可以从 ...
- PowerDesigner的图形工具栏被我关了 怎么才能恢复?就是那个快捷工具栏 图形那个里面有什么放大镜 表 视图什么的
PowerDesigner的图形工具栏被我关了 怎么才能恢复?就是那个快捷工具栏 图形那个里面有什么放大镜 表 视图什么的 工具-->自定义工具栏-->palette选中
- tagName和nodeName的区别
首先介绍DOM里常见的三种节点类型(总共有12种,如docment):元素节点,属性节点以及文本节点,例如<h2 class="title">head</h2 ...
- 微信公众号开发笔记(C#)
这篇文章还不错,使用 .net , 对微信用户的想公众号发送的文字进行回复.比较简单,自己可以修改更复杂的回复. 微信公众号开发笔记(C#) 原文地址 需求分析 根据用户在微信上发送至价值中国公众号 ...
- systemd的原理和适用方法
systemd的原理: https://www.linux.com/learn/tutorials/527639-managing-services-on-linux-with-systemd htt ...
- c# string 数组转 list
string str = "1,11,121,131"; var arr = str.Split(','); List<string> list = new List& ...