题目:
http://acm.hdu.edu.cn/showproblem.php?pid=4123
题意:
给出一颗n个点的有边权的树,Q个询问,给出m,求出连续的最长区间,每个点能到达的最长路径,最大值与最小值得差小于等于m。
思路:
两个dfs,得到每个点可以到达的最大路径。O(n)。
RMQ 求区间最小值最大值。O(nlogn), 询问O(1).
AC.
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <vector>
#include <queue>
#include <map>
using namespace std;
const int maxn = 5e4+5;
int n;
int tot, head[maxn];
struct Edge{
int to, w, next;
}edge[maxn*2];
void init()
{
tot = 0;
memset(head, -1, sizeof(head));
}
void addedge(int u, int v, int w)
{
edge[tot].to = v;
edge[tot].w = w;
edge[tot].next = head[u];
head[u] = tot++;
}
int dis1[maxn], dis2[maxn], to1[maxn], to2[maxn], tor[maxn];
void dfs(int u, int fa)
{
for(int i = head[u]; ~i; i = edge[i].next) {
int v = edge[i].to, w = edge[i].w;
if(v == fa) continue;
//pre[v] = u;
tor[v] = tor[u] + w;
dfs(v, u);
if(dis1[v] + w > dis1[u]) {
dis2[u] = dis1[u]; to2[u] = to1[u];
dis1[u] = dis1[v] + w; to1[u] = v;
}
else if(dis1[v] + w > dis2[u] && dis1[v] + w <= dis1[u]) {
dis2[u] = dis1[v] + w; to2[u] = v;
}
}
}
void dfs1(int u, int fa)
{
for(int i = head[u]; ~i; i = edge[i].next) {
int v = edge[i].to, w = edge[i].w;
if(v == fa) continue;
if(to1[u] == v) {
if(dis1[v] < dis2[u] + w) {
dis2[v] = dis1[v]; to2[v] = to1[v];
dis1[v] = dis2[u] + w; to1[v] = u;
}
else if(dis2[u]+w > dis2[v]) {
dis2[v] = dis2[u] + w; to2[v] = u;
}
}
else {
if(dis1[v] < dis1[u] + w) {
dis2[v] = dis1[v]; to2[v] = to1[v];
dis1[v] = dis1[u] + w; to1[v] = u;
}
else if(dis1[u]+w > dis2[v]) {
dis2[v] = dis1[u] + w; to2[v] = u;
}
}
dfs1(v, u);
}
}
int a[maxn];
int dp1[maxn][20];
int dp2[maxn][20];
int mm[maxn];
void initRMQ(int n)
{
mm[0] = -1;
for(int i = 1;i <= n;i++)
{
mm[i] = ((i&(i-1)) == 0)?mm[i-1]+1:mm[i-1];
dp1[i][0] = a[i];
dp2[i][0] = a[i];
}
for(int j = 1;j <= mm[n];j++)
for(int i = 1;i + (1<<j) - 1 <= n;i++)
{
dp1[i][j] = max(dp1[i][j-1],dp1[i + (1<<(j-1))][j-1]);
dp2[i][j] = min(dp2[i][j-1],dp2[i + (1<<(j-1))][j-1]);
}
}
int rmq(int x,int y)
{
int k = mm[y-x+1];
return max(dp1[x][k],dp1[y-(1<<k)+1][k]) - min(dp2[x][k],dp2[y-(1<<k)+1][k]);
}
int main()
{
//freopen("in", "r", stdin);
int m;
while(~scanf("%d%d", &n, &m)) {
if(n == 0 && m == 0) break;
int u, v, w;
init();
for(int i = 1; i < n; ++i) {
scanf("%d%d%d", &u, &v, &w);
if(u > v) swap(u, v);
addedge(u, v, w);
addedge(v, u, w);
}
for(int i = 1; i <= n; ++i) {
dis1[i] = dis2[i] = 0;
to1[i] = to2[i] = 0;
tor[i] = 0;
}
dfs(1, -1);
dfs1(1, -1);
for(int i = 1; i <= n; ++i) {
dis1[i] = max(dis1[i], tor[i]);
}
for(int i = 1; i <= n; ++i) {
a[i] = dis1[i];
}
initRMQ(n);
int Q;
while(m--)
{
scanf("%d",&Q);
int ans = 0;
int id = 1;
for(int i = 1;i <= n;i++)
{
while(id <= i && rmq(id,i) > Q)id++;
ans = max(ans,i-id+1);
}
printf("%d\n",ans);
}
}
return 0;
}