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. python_way day12 sqlalchemy,原生mysql命令

    python_way day12  sqlalchemy,mysql原生命令 1.sqlalchemy 2.mysql 原生命令 一,sqlalchemy SQLAlchemy本身无法操作数据库,其必 ...

  2. flex布局注意点:

    1.父元素display:flex之后成为伸缩容器,子元素(除了position:absolute或fixed)无论是display:block或者display:inline,都成为了伸缩项目.2. ...

  3. nyoj 19擅长排列的小明 (DFS)

    擅长排列的小明 时间限制:1000 ms  |  内存限制:65535 KB 难度:4   描述 小明十分聪明,而且十分擅长排列计算.比如给小明一个数字5,他能立刻给出1-5按字典序的全排列,如果你想 ...

  4. iOS - UIProgressView

    前言 NS_CLASS_AVAILABLE_IOS(2_0) @interface UIProgressView : UIView <NSCoding> @available(iOS 2. ...

  5. sciencesoftware科学软件

    软件名称 软件分类 二级分类 更新日期 下载 GMS(Groundwater Modeling Solution) 10 地球地理软件 水资源 2014-09-28 下载 Data Desk 7 经济 ...

  6. Redis实践操作之—— keyspace notification(键空间通知)

    一.需求分析: 设置了生存时间的Key,在过期时能不能有所提示? 如果能对过期Key有个监听,如何对过期Key进行一个回调处理? 如何使用 Redis 来实现定时任务? 二.序言: 本文所说的定时任务 ...

  7. effect c++ 口诀。

    常用条款,写成口诀,记住.知其所以,也要时时使用. 1)习惯c++: 联替const初. 2)构造,复制,析构: 要知默,构赋析. 若不需,明拒绝. 构析不调虚. 异不逃析构. 基析要虚函. 赋值操, ...

  8. sqlserver 批量删除存储过程(转)

    sqlserver一次只能删除一个存储过程,如果多了,需要很长时间才能删完,所以写了一段语句,直接就把当然数据库下所有用户自定义的存储过程给drop了.不过使用都请留心,当前打开的数据库哦.下面贴代码 ...

  9. openfire过滤脏话插件,控制消息是否发送

    参考:http://myopenfire.com/article/getarticle/9 package com.myopenfire.plugin; import java.io.File; im ...

  10. 转:C 函数调用栈

    第一篇: 转自:http://kingj.iteye.com/blog/1555017 本文转自  http://blog.csdn.net/eno_rez/article/details/21586 ...