HDU 4123 Bob’s Race(树形DP + 单调队列)
2015-08-08 16:43
363 查看
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4123
题意:给一颗N个点的树,对于每个点i先要找出离它最远的点的距离,设该距离为dis[i],再给M个询问,寻找dis数组中最大值与最小值之差不超过Q的最长连续区间的长度
思路:先找出树的直径的两端点,树上任意点一定是到这两端点中的某一点的距离最远,这样就能处理出dis数组,然后再用两个单调队列去维护区间最大最小值,用类似尺取法的思路去更新答案
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <vector>
#include <utility>
#include <cmath>
#include <queue>
#include <set>
#include <map>
#include <climits>
#include <functional>
#include <deque>
#include <ctime>
#define lson l, mid, rt << 1
#define rson mid + 1, r, rt << 1 | 1
#pragma comment(linker, "/STACK:102400000,102400000")
using namespace std;
typedef long long ll;
const int maxn = 50010;
int cnt, head[maxn];
int dis1[maxn], dis2[maxn], dis[maxn];
int n, m;
struct edge
{
int to, w, next;
} e[maxn << 1];
void init()
{
cnt = 0;
memset(head, -1, sizeof(head));
}
void addedge(int u, int v, int w)
{
e[cnt].to = v;
e[cnt].w = w;
e[cnt].next = head[u];
head[u] = cnt++;
}
void dfs1(int u)
{
for (int i = head[u]; ~i; i = e[i].next)
{
int v = e[i].to;
if (dis1[v] == -1)
{
dis1[v] = dis1[u] + e[i].w;
dfs1(v);
}
}
}
void dfs2(int u)
{
for (int i = head[u]; ~i; i = e[i].next)
{
int v = e[i].to;
if (dis2[v] == -1)
{
dis2[v] = dis2[u] + e[i].w;
dfs2(v);
}
}
}
void tree_Dia()
{
int u, v, len;
memset(dis1, -1, sizeof(dis1));
dis1[1] = 0;
dfs1(1);
len = 0;
for (int i = 1; i <= n; i++)
{
if (dis1[i] > len)
{
len = dis1[i];
u = i;
}
}
memset(dis1, -1, sizeof(dis1));
dis1[u] = 0;
dfs1(u);
len = 0;
for (int i = 1; i <= n; i++)
{
if (dis1[i] > len)
{
len = dis1[i];
v = i;
}
}
memset(dis2, -1, sizeof(dis2));
dis2[v] = 0;
dfs2(v);
for (int i = 1; i <= n; i++)
dis[i] = max(dis1[i], dis2[i]);
}
int qmi[maxn], qma[maxn];
void solve(int q)
{
int f1 = 0, r1 = 0;
int f2 = 0, r2 = 0;
int ans = 0, l = 0;
for (int i = 1; i <= n; i++)
{
while (f1 < r1 && dis[qmi[r1 - 1]] >= dis[i]) r1--;
qmi[r1++] = i;
while (f2 < r2 && dis[qma[r2 - 1]] <= dis[i]) r2--;
qma[r2++] = i;
while (dis[qma[f2]] - dis[qmi[f1]] > q)
{
l++;
if (qmi[f1] <= l) f1++;
if (qma[f2] <= l) f2++;
}
ans = max(ans, i - l);
}
printf("%d\n", ans);
}
int main()
{
while (~scanf("%d%d", &n, &m) && (n + m))
{
init();
for (int i = 0; i < n - 1; i++)
{
int u, v, w;
scanf("%d%d%d", &u, &v, &w);
addedge(u, v, w);
addedge(v, u, w);
}
tree_Dia();
while (m--)
{
int q;
scanf("%d", &q);
solve(q);
}
}
return 0;
}
题意:给一颗N个点的树,对于每个点i先要找出离它最远的点的距离,设该距离为dis[i],再给M个询问,寻找dis数组中最大值与最小值之差不超过Q的最长连续区间的长度
思路:先找出树的直径的两端点,树上任意点一定是到这两端点中的某一点的距离最远,这样就能处理出dis数组,然后再用两个单调队列去维护区间最大最小值,用类似尺取法的思路去更新答案
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <vector>
#include <utility>
#include <cmath>
#include <queue>
#include <set>
#include <map>
#include <climits>
#include <functional>
#include <deque>
#include <ctime>
#define lson l, mid, rt << 1
#define rson mid + 1, r, rt << 1 | 1
#pragma comment(linker, "/STACK:102400000,102400000")
using namespace std;
typedef long long ll;
const int maxn = 50010;
int cnt, head[maxn];
int dis1[maxn], dis2[maxn], dis[maxn];
int n, m;
struct edge
{
int to, w, next;
} e[maxn << 1];
void init()
{
cnt = 0;
memset(head, -1, sizeof(head));
}
void addedge(int u, int v, int w)
{
e[cnt].to = v;
e[cnt].w = w;
e[cnt].next = head[u];
head[u] = cnt++;
}
void dfs1(int u)
{
for (int i = head[u]; ~i; i = e[i].next)
{
int v = e[i].to;
if (dis1[v] == -1)
{
dis1[v] = dis1[u] + e[i].w;
dfs1(v);
}
}
}
void dfs2(int u)
{
for (int i = head[u]; ~i; i = e[i].next)
{
int v = e[i].to;
if (dis2[v] == -1)
{
dis2[v] = dis2[u] + e[i].w;
dfs2(v);
}
}
}
void tree_Dia()
{
int u, v, len;
memset(dis1, -1, sizeof(dis1));
dis1[1] = 0;
dfs1(1);
len = 0;
for (int i = 1; i <= n; i++)
{
if (dis1[i] > len)
{
len = dis1[i];
u = i;
}
}
memset(dis1, -1, sizeof(dis1));
dis1[u] = 0;
dfs1(u);
len = 0;
for (int i = 1; i <= n; i++)
{
if (dis1[i] > len)
{
len = dis1[i];
v = i;
}
}
memset(dis2, -1, sizeof(dis2));
dis2[v] = 0;
dfs2(v);
for (int i = 1; i <= n; i++)
dis[i] = max(dis1[i], dis2[i]);
}
int qmi[maxn], qma[maxn];
void solve(int q)
{
int f1 = 0, r1 = 0;
int f2 = 0, r2 = 0;
int ans = 0, l = 0;
for (int i = 1; i <= n; i++)
{
while (f1 < r1 && dis[qmi[r1 - 1]] >= dis[i]) r1--;
qmi[r1++] = i;
while (f2 < r2 && dis[qma[r2 - 1]] <= dis[i]) r2--;
qma[r2++] = i;
while (dis[qma[f2]] - dis[qmi[f1]] > q)
{
l++;
if (qmi[f1] <= l) f1++;
if (qma[f2] <= l) f2++;
}
ans = max(ans, i - l);
}
printf("%d\n", ans);
}
int main()
{
while (~scanf("%d%d", &n, &m) && (n + m))
{
init();
for (int i = 0; i < n - 1; i++)
{
int u, v, w;
scanf("%d%d%d", &u, &v, &w);
addedge(u, v, w);
addedge(v, u, w);
}
tree_Dia();
while (m--)
{
int q;
scanf("%d", &q);
solve(q);
}
}
return 0;
}
相关文章推荐
- hdu 5363
- C语言文件读写操作总结
- Leetcode #109 Convert Sorted List to Binary Search Tree
- Android四大组件之BroadCast(续)
- cocos2d-x综述(源自cocos2d-x中文网)
- C++面向对象程序设计 笔记3 (面向对象部分)
- OS-8
- codeforces535C:Tavas and Karafs(二分)
- OC-@property后的修饰符及其用法小结
- Linux根文件系统详解
- 每天学点java—Object类
- 黑马程序员-----Java基础-----数组!
- JAVA学习笔记(五)
- 关系模型基本概念
- UVA 10441 Catenyms【欧拉路】
- CodeForces 492B
- 极简三位数加减出题软件
- IIS6 + PHP 访问页面出现:需要进行身份验证的问题
- 关于自定义标签当中的unable to find setter method for attribute:xxx错误 小记
- Android widget 之RemoteView