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] ...
随机推荐
- python_way day12 sqlalchemy,原生mysql命令
python_way day12 sqlalchemy,mysql原生命令 1.sqlalchemy 2.mysql 原生命令 一,sqlalchemy SQLAlchemy本身无法操作数据库,其必 ...
- flex布局注意点:
1.父元素display:flex之后成为伸缩容器,子元素(除了position:absolute或fixed)无论是display:block或者display:inline,都成为了伸缩项目.2. ...
- nyoj 19擅长排列的小明 (DFS)
擅长排列的小明 时间限制:1000 ms | 内存限制:65535 KB 难度:4 描述 小明十分聪明,而且十分擅长排列计算.比如给小明一个数字5,他能立刻给出1-5按字典序的全排列,如果你想 ...
- iOS - UIProgressView
前言 NS_CLASS_AVAILABLE_IOS(2_0) @interface UIProgressView : UIView <NSCoding> @available(iOS 2. ...
- sciencesoftware科学软件
软件名称 软件分类 二级分类 更新日期 下载 GMS(Groundwater Modeling Solution) 10 地球地理软件 水资源 2014-09-28 下载 Data Desk 7 经济 ...
- Redis实践操作之—— keyspace notification(键空间通知)
一.需求分析: 设置了生存时间的Key,在过期时能不能有所提示? 如果能对过期Key有个监听,如何对过期Key进行一个回调处理? 如何使用 Redis 来实现定时任务? 二.序言: 本文所说的定时任务 ...
- effect c++ 口诀。
常用条款,写成口诀,记住.知其所以,也要时时使用. 1)习惯c++: 联替const初. 2)构造,复制,析构: 要知默,构赋析. 若不需,明拒绝. 构析不调虚. 异不逃析构. 基析要虚函. 赋值操, ...
- sqlserver 批量删除存储过程(转)
sqlserver一次只能删除一个存储过程,如果多了,需要很长时间才能删完,所以写了一段语句,直接就把当然数据库下所有用户自定义的存储过程给drop了.不过使用都请留心,当前打开的数据库哦.下面贴代码 ...
- openfire过滤脏话插件,控制消息是否发送
参考:http://myopenfire.com/article/getarticle/9 package com.myopenfire.plugin; import java.io.File; im ...
- 转:C 函数调用栈
第一篇: 转自:http://kingj.iteye.com/blog/1555017 本文转自 http://blog.csdn.net/eno_rez/article/details/21586 ...