给出一棵树,编号为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+线段树的更多相关文章

  1. POJ 3162.Walking Race 树形dp 树的直径

    Walking Race Time Limit: 10000MS   Memory Limit: 131072K Total Submissions: 4123   Accepted: 1029 Ca ...

  2. POJ - 3162 Walking Race 树形dp 单调队列

    POJ - 3162Walking Race 题目大意:有n个训练点,第i天就选择第i个训练点为起点跑到最远距离的点,然后连续的几天里如果最远距离的最大值和最小值的差距不超过m就可以作为观测区间,问这 ...

  3. 【题解】poj 3162 Walking Race 树形dp

    题目描述 Walking RaceTime Limit: 10000MS Memory Limit: 131072KTotal Submissions: 4941 Accepted: 1252Case ...

  4. POJ 3162 Walking Race 树形dp 优先队列

    http://poj.org/problem?id=3162 题意 :  一棵n个节点的树.wc爱跑步,跑n天,第i天从第i个节点开始跑步,每次跑到距第i个节点最远的那个节点(产生了n个距离),现在要 ...

  5. POJ 3162 Walking Race(树形dp+单调队列 or 线段树)

    http://poj.org/problem?id=3162 题意:一棵n个节点的树.有一个屌丝爱跑步,跑n天,第i天从第i个节点开始跑步,每次跑到距第i个节点最远的那个节点(产生了n个距离),现在要 ...

  6. Codeforces 671D. Roads in Yusland(树形DP+线段树)

    调了半天居然还能是线段树写错了,药丸 这题大概是类似一个树形DP的东西.设$dp[i]$为修完i这棵子树的最小代价,假设当前点为$x$,但是转移的时候我们不知道子节点到底有没有一条越过$x$的路.如果 ...

  7. hdu5293 Tree chain problem 树形dp+线段树

    题目:pid=5293">http://acm.hdu.edu.cn/showproblem.php?pid=5293 在一棵树中,给出若干条链和链的权值.求选取不相交的链使得权值和最 ...

  8. poj3162(树形dp+线段树求最大最小值)

    题目链接:https://vjudge.net/problem/POJ-3162 题意:给一棵树,求每个结点的树上最远距离,记为a[i],然后求最大区间[l,r]满足区间内的max(a[i])-min ...

  9. Codeforces Round #530 (Div. 2) F (树形dp+线段树)

    F. Cookies 链接:http://codeforces.com/contest/1099/problem/F 题意: 给你一棵树,树上有n个节点,每个节点上有ai块饼干,在这个节点上的每块饼干 ...

随机推荐

  1. C++@冒号(:)和双冒号(::)的用法

    转自:http://blog.csdn.net/zimingjushi/article/details/6549390 1.冒号(:)用法 (1)表示机构内位域的定义(即该变量占几个bit空间) ty ...

  2. [hdu 3605]Escape

    这题的做法非常直观,却又非常不直观 先容许我吐一下槽吧~作者你的英语是读到火星上去了喵? 题目大体是说人类要移民,然后有 n 个人, m 个星球 每个人都有 m 个 0 . 1 数码表示他能否移民到该 ...

  3. Java theory and practice

    This content is part of the series: Java theory and practice A brief history of garbage collection A ...

  4. memory CPU cache books

    http://www.amazon.com/Consistency-Coherence-Synthesis-Lectures-Architecture/dp/1608455645/ref=pd_sim ...

  5. KMP字符串模式匹配学习笔记

    KMP算法实验 1.编程计算模式串(子串)的next值.2.利用KMP算法在主串中找到模式串的位置. 参考代码:---------int getNexlVal( char * s,  int j)// ...

  6. android屏幕亮度

    /** * 获得当前屏幕亮度的模式 * SCREEN_BRIGHTNESS_MODE_AUTOMATIC=1 为自动调节屏幕亮度 * SCREEN_BRIGHTNESS_MODE_MANUAL=0 为 ...

  7. 纯CSS绘制三角形(各种角度)

    我们的网页因为 CSS 而呈现千变万化的风格.这一看似简单的样式语言在使用中非常灵活,只要你发挥创意就能实现很多比人想象不到的效果.特别是随着 CSS3 的广泛使用,更多新奇的 CSS 作品涌现出来. ...

  8. 使用Path语法取得对象的值

    借鉴了http://stackoverflow.com/questions/4473928/c-sharp-dynamic-string-property-path     public class ...

  9. 微信网页授权获取用户基本信息--PHP

    现在就说说怎么通过网页授权获取用户基本信息(国家,省,市,昵称)等. 必要条件: 1)公众号认证 2)有网页授权获取用户基本信息的权限接口 注意:最近有朋友说:在公众平台申请的测试号,会出现无法取到用 ...

  10. Android 广播大全 Intent Action 事件

    Intent.ACTION_AIRPLANE_MODE_CHANGED; //关闭或打开飞行模式时的广播 Intent.ACTION_BATTERY_CHANGED; //充电状态,或者电池的电量发生 ...