HDU 4123(树的直径+单调队列)
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
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)
1 2 3
2 3 4
4 5 3
3 4 2
1
2
3
4
5
0 0
3
3
3
5
#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 ;
}
#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(树的直径+单调队列)的更多相关文章
- HDU 4123 Bob's Race:树的直径 + 单调队列 + st表
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4123 题意: 给你一棵树,n个节点,每条边有长度. 然后有m个询问,每个询问给定一个q值. 设dis[ ...
- HDU 4123 Bob’s Race 树的直径+单调队列
题意: 给定n个点的带边权树Q个询问. 以下n-1行给出树 以下Q行每行一个数字表示询问. 首先求出dp[N] :dp[i]表示i点距离树上最远点的距离 询问u, 表示求出 dp 数组中最长的连续序列 ...
- POJ 3162 Walking Race(树的直径+单调队列)
题目大意:对一棵树,求出从每个结点出发能到走的最长距离(每个结点最多只能经过一次),将这些距离按排成一个数组得到dis[1],dis[2],dis[3]……dis[n] ,在数列的dis中求一个最长的 ...
- bzoj 1999: [Noip2007]Core树网的核【树的直径+单调队列】
我要懒死了,所以依然是lyd的课件截图 注意是min{max(max(d[uk]),dis(u1,ui),dis(uj,un))},每次都从这三个的max里取min #include<iostr ...
- 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 ...
- hdu 5945 Fxx and game(单调队列优化DP)
题目链接:hdu 5945 Fxx and game 题意: 让你从x走到1的位置,问你最小的步数,给你两种走的方式,1.如果k整除x,那么你可以从x走一步到k.2.你可以从x走到j,j+t<= ...
- hdu 3410 Passing the Message(单调队列)
题目链接:hdu 3410 Passing the Message 题意: 说那么多,其实就是对于每个a[i],让你找他的从左边(右边)开始找a[j]<a[i]并且a[j]=max(a[j])( ...
- 大视野 1012: [JSOI2008]最大数maxnumber(线段树/ 树状数组/ 单调队列/ 单调栈/ rmq)
1012: [JSOI2008]最大数maxnumber Time Limit: 3 Sec Memory Limit: 162 MBSubmit: 9851 Solved: 4318[Submi ...
- BZOJ 1396:识别子串 SA+树状数组+单调队列
1396: 识别子串 Time Limit: 10 Sec Memory Limit: 162 MBSubmit: 381 Solved: 243[Submit][Status][Discuss] ...
随机推荐
- 8.Methods(一)
1.Instance Constructors and Classes (Reference Types) Constructors methods : 1.allow an instance of ...
- Windows Internals学习笔记(四)Trap Dispatching
参考资料: 1. <Windows Internals> 知识点: ● 陷阱trap:它是一种处理器机制,用以在某一异常或中断出现时,捕捉该执行线程,并将其控制权转交到操作系统中某一固定位 ...
- 2dx中文乱码问题
我们的代码里面有一个bug 为了跟之前兼容的策划导表工具兼容 导表工具导出的excel全部都是ansi的 为了兼容就只能手动改成utf 8 无bom格式 后来策划嫌烦了 就让在程序段处理这个 研究了好 ...
- Sublime Text 2 一些常用的快捷键
atrl+F查找后按F3或者ctrl+F3,是查找下一个,shift+F3是查找上一个alt+f3高亮所有的查找的ctrl+h 查找并替换 ctrl+left是向左一个单词跳跃,right同理 ctr ...
- DZY Loves Chessboard
DescriptionDZY loves chessboard, and he enjoys playing with it. He has a chessboard of n rows and m ...
- mysql概要(十)触发器
1触发器可监视增删改,并触发增删改操作. 针对一些逻辑关联密切的操作,而不必手动多次操作. 2.要素: 3.语法: 补充:mysql可以设置结束符,不必是“:”来结束标志,可使用 3.1简单的例子: ...
- NEU校园网登录器
http://www.cnblogs.com/weidiao/p/5124106.html 改自学长的博客. 我们的目标是写一个程序实现自动登录校园网.而这基于的是表单的post机制. 输入校园网网址 ...
- ubuntu源码安装django
由于用pip install django方法安装太慢,而且容易报错,故使用源码的方式安装 方法: 下载源码包:https://www.djangoproject.com/download/ 输入以下 ...
- JavaScript设计模式-单例模式、模块模式(转载 学习中。。。。)
(转载地址:http://technicolor.iteye.com/blog/1409656) 之前在<JavaScript小特性-面向对象>里面介绍过JavaScript面向对象的特性 ...
- Android控件之CheckBox(复选框控件)
一.有两种状态: 选中状态(true).未选中状态(false) 二.属性 android:id = "@+id/checkbox" android:layout_width=&q ...