您的位置:首页 > 其它

POJ 3162 Walking Race(树形DP + 单调队列)

2014-11-10 21:55 363 查看
题目链接:http://poj.org/problem?id=3162

题意:对一棵树,求出从每个结点出发能到走的最长距离(每个结点最多只能走一次),将这些距离按排成一个数组得到d[1],d[2],d[3]……d
,在数列的d中求一个最长的区间,使得区间中的最大值与最小值的差不超过m。

思路:先求出树的直径,对于树中任意结点i,到树的直径的2个端点的距离的较大者即为最长距离d[i]。得到数组d后,用2个单调队列分别维护最大与最小值,扫描d数组,同时更新答案。

#include <iostream>
#include <algorithm>
#include <cstring>
#include <string>
#include <cstdio>
#include <cmath>
#include <queue>
#include <map>
#include <set>

using namespace std;

const int maxn = 1000010;
const int maxm = 5000;
const int inf = 0x3f3f3f3f;

int n, m;
int dis1[maxn], dis2[maxn], d[maxn];
int qmin[maxn], qmax[maxn];

struct edge
{
int to, w, nxt;
} e[maxn * 2];

int cnt;
int head[maxn];

void init()
{
cnt = 0;
memset(head, -1, sizeof(head));
}

void add(int u, int v, int w)
{
e[cnt].to = v;
e[cnt].w = w;
e[cnt].nxt = head[u];
head[u] = cnt++;
}

void dfs1(int u)
{
for(int i = head[u]; ~i; i = e[i].nxt)
{
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].nxt)
{
int v = e[i].to;
if(dis2[v] == -1)
{
dis2[v] = dis2[u] + e[i].w;
dfs2(v);
}
}
}

void solve()
{
int ans = 0, i, j;
int f1, r1, f2, r2;
f1 = r1 = 0;
f2 = r2 = 0;
for(i = 1, j = 1; j <= n; j++)
{
while(r1 > f1 && d[qmax[r1 - 1]] <= d[j]) r1--;
qmax[r1++] = j;

while(r2 > f2 && d[qmin[r2 - 1]] >= d[j]) r2--;
qmin[r2++] = j;

if(d[qmax[f1]] - d[qmin[f2]] > m)
{
ans = max(ans, j - i);
while(d[qmax[f1]] - d[qmin[f2]] > m)
{
i = min(qmax[f1], qmin[f2]) + 1;
while(r1 > f1 && qmax[f1] < i) f1++;
while(r2 > f2 && qmin[f2] < i) f2++;
}
}
}
ans = max(ans, j - i);
printf("%d\n", ans);
}

int main()
{
while(~scanf("%d%d", &n, &m))
{
init();
for(int i = 2; i <= n; i++)
{
int v, w;
scanf("%d%d", &v, &w);
add(i, v, w);
add(v, i, w);
}
int len = 0;
int u, v;
memset(dis1, -1, sizeof(dis1));
dis1[1] = 0;
dfs1(1);
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);
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++)
{
//printf("%d %d\n", dis1[i], dis2[i]);
d[i] = max(dis1[i], dis2[i]);
}
solve();
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: