Bob’s Race

Time Limit: 5000/2000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 2833    Accepted Submission(s): 917

Problem Description
Bob wants to hold a race to encourage people to do sports. He has got trouble in choosing the route. There are N houses and N - 1 roads in his village. Each road connects two houses, and all houses are connected together. To make the race more interesting, he requires that every participant must start from a different house and run AS FAR AS POSSIBLE without passing a road more than once. The distance difference between the one who runs the longest distance and the one who runs the shortest distance is called “race difference” by Bob. Bob does not want the “race difference”to be more than Q. The houses are numbered from 1 to N. Bob wants that the No. of all starting house must be consecutive. He is now asking you for help. He wants to know the maximum number of starting houses he can choose, by other words, the maximum number of people who can take part in his race.
 
Input
There are several test cases.
The first line of each test case contains two integers N and M. N is the number of houses, M is the number of queries.
The following N-1 lines, each contains three integers, x, y and z, indicating that there is a road of length z connecting house x and house y.
The following M lines are the queries. Each line contains an integer Q, asking that at most how many people can take part in Bob’s race according to the above mentioned rules and under the condition that the“race difference”is no more than Q.

The input ends with N = 0 and M = 0.

(N<=50000 M<=500 1<=x,y<=N 0<=z<=5000 Q<=10000000)

 
Output
For each test case, you should output the answer in a line for each query.
 
Sample Input
5 5
1 2 3
2 3 4
4 5 3
3 4 2
1
2
3
4
5
0 0
 
Sample Output
1
3
3
3
5
 
Source
 
一、求树的直径问题
     树的直径:树中距离最远的两点间的距离。
     1、树形dp
      首先建树,新学的建树方式,一般我都是直接vector的存点的。
      然后dfs求出每个节点到所有叶子的最大距离。
      最重要的一步,求出跟到除当前子节点之外的所有分支的最大距离,然后加上跟到当前子节点的距离,向上更新。
      先贴一份别人的代码:
      Hdu2196  
#include <stdio.h>
#include <string.h>
#define MAX 10001
#define max(a,b) (a)>(b)?(a):(b) struct node { int v,len,sum;
node *next;
}*head[MAX*],tree[MAX*];
__int64 dp[MAX];
int n,ptr,vis[MAX]; void Initial() { ptr = ;
memset(dp,,sizeof(dp));
memset(vis,,sizeof(vis));
memset(head,NULL,sizeof(head));
}
void AddEdge(int x,int y,int len) { tree[ptr].v = y,tree[ptr].len = len;
tree[ptr].next = head[x],head[x] = &tree[ptr++];
//printf("ptr : %d **** tree[ptr].v: ")
tree[ptr].v = x,tree[ptr].len = len;
tree[ptr].next = head[y],head[y] = &tree[ptr++];
}
void Dfs(int v) { vis[v] = ;
node *p = head[v]; while (p != NULL) { if (!vis[p->v]) { Dfs(p->v);
dp[v] = max(dp[v],dp[p->v]+p->len);
p->sum = dp[p->v] + p->len;
}
p = p->next;
}
}
void Tree_DP(int pa,int son) { if (vis[son]) return;
vis[son] = ;
int i,j,k,maxx = ; node *p = head[pa];
while (p != NULL) {
//找到父节点除son外其他分支的最大价值
if (p->v != son)
maxx = max(maxx,p->sum);
p = p->next;
} p = head[son];
while (p != NULL) { if (p->v == pa) {
//这一步至关重要,往上更新,才能保证每步都得到最优解
p->sum = p->len + maxx;
break;
}
p = p->next;
} p = head[son];
while (p != NULL) {
//每次都更新当前节点,并往下递归计算,父节点会因为vis=1而不计算
dp[son] = max(dp[son],p->sum);
Tree_DP(son,p->v);
p = p->next;
}
} int main()
{
int i,j,k,a,b; while (scanf("%d",&n) != EOF) { Initial();
for (i = ; i <= n; ++i) { scanf("%d%d",&a,&b);
AddEdge(i,a,b);
} Dfs();
memset(vis,,sizeof(vis));
node *p = head[];
while (p != NULL) { Tree_DP(,p->v);
p = p->next;
}
for (i = ; i <= n; ++i)
printf("%I64d\n",dp[i]);
}
}

还有一种其他的理解,这种我感觉比较好理解的。

先建一棵有根数。

求出每个节点到叶子的最长距离和次长距离,并记录到最长距离要经过的子节点(与其相连那一个)。

接下来分两种情况:

(1)当前节点的最长距离经过某子节点,则某子节点的最长距离为当前节点的次长距离和某子节点的最长距离的最大值加当前节点到某子节点的距离

(2)当前节点的最长距离不经过某子节点,则某子节点的最长距离为当前节点的最长距离和某子节点的最长距离的最大值加当前节点到某子节点的距离

更新子节点

hdu2196

#include <cstdio>
#include <iostream>
#include <sstream>
#include <cmath>
#include <cstring>
#include <cstdlib>
#include <string>
#include <vector>
#include <map>
#include <set>
#include <queue>
#include <stack>
#include <algorithm>
using namespace std;
#define ll long long
#define _cle(m, a) memset(m, a, sizeof(m))
#define repu(i, a, b) for(int i = a; i < b; i++)
#define repd(i, a, b) for(int i = b; i >= a; i--)
#define sfi(n) scanf("%d", &n)
#define sfl(n) scanf("%I64d", &n)
#define pfi(n) printf("%d\n", n)
#define pfl(n) printf("%I64d\n", n)
#define MAXN 1000005 struct Node
{
int v, len;
Node* next;
}*head[MAXN], tree[MAXN * ];
bool vis[MAXN];
int c = ;
int last[MAXN];
ll maxlen[MAXN], smaxlen[MAXN];
ll dp[MAXN];
void init()
{
c = ;
_cle(vis, );
_cle(head, NULL);
_cle(dp, );
_cle(last, );
return ;
} void Add_Edge(int x, int y, int len)
{
tree[c].v = y, tree[c].len = len;
tree[c].next = head[x], head[x] = &tree[c++];
tree[c].v = x, tree[c].len = len;
tree[c].next = head[y], head[y] = &tree[c++];
} void dfs(int fa, int pre)
{
if(vis[fa]) return ;
vis[fa] = ;
Node* p = head[fa];
while(p != NULL)
{
dfs(p -> v, fa);
p = p -> next;
}
int maxn = ;
p = head[fa];
while(p != NULL)
{
if(maxn < p -> len + maxlen[p -> v] && p -> v != pre)
{
maxn = p -> len + maxlen[p -> v];
last[fa] = p -> v;
}
p = p -> next;
}
maxlen[fa] = maxn;
maxn = ;
p = head[fa];
while(p != NULL)
{
if(p -> v != pre && p -> v != last[fa] && maxn < p -> len + maxlen[p -> v])
maxn = p -> len + maxlen[p -> v];
p = p -> next;
}
smaxlen[fa] = maxn;
return ;
} void DP(int fa)
{
vis[fa] = ;
Node* p = head[fa];
while(p != NULL)
{
if(!vis[p -> v])
{
if(last[fa] != p -> v)
dp[p -> v] = max(dp[fa], maxlen[fa]) + p -> len;
else
dp[p -> v] = max(dp[fa], smaxlen[fa]) + p -> len;
DP(p -> v);
}
p = p -> next;
}
return ;
} int main()
{
int n;
while(~sfi(n))
{
init();
int x, y, len;
repu(i, , n + )
{
sfi(y), sfi(len);
Add_Edge(i, y, len);
} dfs(, -);
_cle(vis, );
DP();
repu(i, , n + )
{
// pfl(smaxlen[i]);
pfl(max(maxlen[i], dp[i]));
}
}
return ;
}
 2、利用了树的直径的一个性质:距某个点最远的叶子节点一定是树的某一条直径的端点。这样就可以首先任取一个点,bfs求出离其最远的点,在用同样的方法求出离这个叶子节点最远的点,此时两点间的距离就是树的直径。 
Poj1985
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<vector>
#include<queue>
using namespace std;
const int maxn = ;
vector<int> son[maxn], w[maxn];
bool vis[maxn], viss[maxn];
int f[maxn];
int bfs(int root){
int i, j, k;
int ans = root, maxx = ;
queue<int> q;
memset(vis,,sizeof(vis));
memset(f,,sizeof(f));
q.push(root);
vis[root] = ;f[root] = ;viss[root] = ;
while(!q.empty()){
root = q.front();
q.pop();
for(i=;i<son[root].size();i++){
if(vis[son[root][i]]==){
q.push(son[root][i]);
vis[son[root][i]] = ;viss[son[root][i]] = ;
f[son[root][i]] = f[root]+w[root][i];
if(maxx<f[son[root][i]]){
maxx = f[son[root][i]];
ans = son[root][i];
}
}
}
}
return ans;
}
int solve(int root){
int u, v;
u = bfs(root);
v = bfs(u);
return f[v];
}
int main(){
int i, j, k, n, m;
int x1, x2, l, u;
int res;
char opt;
while(~scanf("%d%d",&n,&m)){
for(i=;i<=n;i++){
son[i].clear();
w[i].clear();
}
for(i=;i<m;i++){
scanf("%d%d%d",&x1,&x2,&l);
scanf(" %c",&opt);
son[x1].push_back(x2);w[x1].push_back(l);
son[x2].push_back(x1);w[x2].push_back(l);
}
res = ;
memset(viss,,sizeof(vis));
for(i=;i<=n;i++){
if(viss[i]==){
res = max(res,solve(i));
}
}
printf("%d\n",res);
}
return ;
}

二、单调队列问题

就是单调队列+类似尺取法吧

下面是完整代码:

#include <cstdio>
#include <iostream>
#include <sstream>
#include <cmath>
#include <cstring>
#include <cstdlib>
#include <string>
#include <vector>
#include <map>
#include <set>
#include <queue>
#include <stack>
#include <algorithm>
using namespace std;
#define ll long long
#define _cle(m, a) memset(m, a, sizeof(m))
#define repu(i, a, b) for(int i = a; i < b; i++)
#define repd(i, a, b) for(int i = b; i >= a; i--)
#define sfi(n) scanf("%d", &n)
#define sfl(n) scanf("%I64d", &n)
#define pfi(n) printf("%d\n", n)
#define pfl(n) printf("%I64d\n", n)
#define MAXN 1000005 struct Node
{
int v, len;
Node* next;
}*head[MAXN], tree[MAXN * ];
bool vis[MAXN];
int c = ;
int last[MAXN];
ll maxlen[MAXN], smaxlen[MAXN];
ll dp[MAXN];
ll p[MAXN];
void init()
{
c = ;
_cle(vis, );
_cle(head, NULL);
_cle(dp, );
_cle(last, );
return ;
} void Add_Edge(int x, int y, int len)
{
tree[c].v = y, tree[c].len = len;
tree[c].next = head[x], head[x] = &tree[c++];
tree[c].v = x, tree[c].len = len;
tree[c].next = head[y], head[y] = &tree[c++];
} void dfs(int fa, int pre)
{
if(vis[fa]) return ;
vis[fa] = ;
Node* p = head[fa];
while(p != NULL)
{
dfs(p -> v, fa);
p = p -> next;
}
int maxn = ;
p = head[fa];
while(p != NULL)
{
if(maxn < p -> len + maxlen[p -> v] && p -> v != pre)
{
maxn = p -> len + maxlen[p -> v];
last[fa] = p -> v;
}
p = p -> next;
}
maxlen[fa] = maxn;
maxn = ;
p = head[fa];
while(p != NULL)
{
if(p -> v != pre && p -> v != last[fa] && maxn < p -> len + maxlen[p -> v])
maxn = p -> len + maxlen[p -> v];
p = p -> next;
}
smaxlen[fa] = maxn;
return ;
} void DP(int fa)
{
vis[fa] = ;
Node* p = head[fa];
while(p != NULL)
{
if(!vis[p -> v])
{
if(last[fa] != p -> v)
dp[p -> v] = max(dp[fa], maxlen[fa]) + p -> len;
else
dp[p -> v] = max(dp[fa], smaxlen[fa]) + p -> len;
DP(p -> v);
}
p = p -> next;
}
return ;
} int main()
{
int n, m;
while(sfi(n), sfi(m), n + m)
{
init();
int x, y, len;
repu(i, , n)
{
sfi(x), sfi(y), sfi(len);
Add_Edge(x, y, len);
} dfs(, -);
_cle(vis, );
DP();
repu(i, , n + ) p[i] = max(maxlen[i], dp[i]);
int Q;
repu(i, , m)
{
scanf("%d", &Q);
ll maxnum = ;
ll maxn = p[];
ll minn = p[];
ll num = ;
int last, maxp, minp;
last = maxp = minp = ;
repu(j, , n + )
{
if(p[j] > maxn)
{
if(p[j] - minn > Q)
{
maxnum = max(maxnum, num);
num = ;
j = min(minp + , maxp + );
maxn = minn = p[j];
maxp = minp = j;
}
else num++, maxn = p[j], maxp = j;
}
else if(p[j] < minn)
{
if(maxn - p[j] > Q)
{
maxnum = max(maxnum, num);
num = ;
j = min(minp + , maxp + );
maxn = minn = p[j];
maxp = minp = j;
}
else num++, minn = p[j], minp = j;
}
else num++;
}
maxnum = max(maxnum, num);
pfl(maxnum);
}
}
return ;
}

HDU 4123(树的直径+单调队列)的更多相关文章

  1. HDU 4123 Bob's Race:树的直径 + 单调队列 + st表

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4123 题意: 给你一棵树,n个节点,每条边有长度. 然后有m个询问,每个询问给定一个q值. 设dis[ ...

  2. HDU 4123 Bob’s Race 树的直径+单调队列

    题意: 给定n个点的带边权树Q个询问. 以下n-1行给出树 以下Q行每行一个数字表示询问. 首先求出dp[N] :dp[i]表示i点距离树上最远点的距离 询问u, 表示求出 dp 数组中最长的连续序列 ...

  3. POJ 3162 Walking Race(树的直径+单调队列)

    题目大意:对一棵树,求出从每个结点出发能到走的最长距离(每个结点最多只能经过一次),将这些距离按排成一个数组得到dis[1],dis[2],dis[3]……dis[n] ,在数列的dis中求一个最长的 ...

  4. bzoj 1999: [Noip2007]Core树网的核【树的直径+单调队列】

    我要懒死了,所以依然是lyd的课件截图 注意是min{max(max(d[uk]),dis(u1,ui),dis(uj,un))},每次都从这三个的max里取min #include<iostr ...

  5. HDU - 5289:Assignment(单调队列||二分+RMQ||二分+线段树)

    Tom owns a company and he is the boss. There are n staffs which are numbered from 1 to n in this com ...

  6. hdu 5945 Fxx and game(单调队列优化DP)

    题目链接:hdu 5945 Fxx and game 题意: 让你从x走到1的位置,问你最小的步数,给你两种走的方式,1.如果k整除x,那么你可以从x走一步到k.2.你可以从x走到j,j+t<= ...

  7. hdu 3410 Passing the Message(单调队列)

    题目链接:hdu 3410 Passing the Message 题意: 说那么多,其实就是对于每个a[i],让你找他的从左边(右边)开始找a[j]<a[i]并且a[j]=max(a[j])( ...

  8. 大视野 1012: [JSOI2008]最大数maxnumber(线段树/ 树状数组/ 单调队列/ 单调栈/ rmq)

    1012: [JSOI2008]最大数maxnumber Time Limit: 3 Sec  Memory Limit: 162 MBSubmit: 9851  Solved: 4318[Submi ...

  9. BZOJ 1396:识别子串 SA+树状数组+单调队列

    1396: 识别子串 Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 381  Solved: 243[Submit][Status][Discuss] ...

随机推荐

  1. JMS【三】--ActiveMQ简单的HelloWorld实例

    第一篇博文JMS[一]--JMS基本概念,我们介绍了JMS的两种消息模型:点对点和发布订阅模型,以及消息被消费的两个方式:同步和异步,JMS编程模型的对象,最后说了JMS的优点. 第二篇博文JMS[二 ...

  2. eclipse 设置jvm 内存

    Eclipse 中设置JVM 内存 今天在eclipse 中测试把文档转换为图片的时候,报出了下面的错误: java.lang.OutOfMemoryError: Java heap space 从上 ...

  3. HDU-4514 湫湫系列故事——设计风景线 手动扩栈

    题意:给定一个无向图,首先判定是否成环,然后求一条最长链. 分析:成环用并查集,最长链就是个最简单的树形dp了. #include <cstdlib> #include <cstri ...

  4. JavaWeb学习总结(七)—HttpServletRequest

    一.Request概述 request是Servlet.service()方法的一个参数,类型为javax.servlet.http.HttpServletRequest.在客户端发出每个请求时,服务 ...

  5. Linux系统/etc/init.d目录

    理解Linux系统/etc/init.d目录和/etc/rc.local脚本 http://blog.csdn.net/acs713/article/details/7322082 Linux文件目录 ...

  6. uva 11800 Determine the Shape

    vjudge上题目链接:Determine the Shape 第二道独自 A 出的计算几何水题,题意就是给你四个点,让你判断它是哪种四边形:正方形.矩形.菱形.平行四边形.梯形 or 普通四边形. ...

  7. C++中构造函数调用构造函数

    今天想做道矩阵的题目时,却卡在一些编程细节上了,找了好久才发现原来是在构造函数处出了问题,然后上网百度了下,发现这篇文章说得很好:从一道题谈C++中构造函数调用构造函数,很棒! 还补充一点: 看来自己 ...

  8. junit4 javaee 5.0 jpa SSH 单元测试问题集锦

    本篇文章基于已经实现了ssh集成的demo.项目.具体的ssh项目怎么配置,请参考本文最后 spring环境下的JUnit4测试 1,下载所需jar包: spring-test-3.2.0.RELEA ...

  9. 转:copy initialization

    转自: http://en.cppreference.com/w/cpp/language/copy_initialization copy initialization   C++   C++ la ...

  10. jQuery内置函数 ready

    jQuery给我们提供了一些非常实用的函数 ready:加载函数 传统事件只能绑定一个函数 后面的函数会把前面的函数覆盖 js中用的是  window.onload = function(){}; j ...