题解 幸福的道路
题意:给定一棵树,将树上每个点的最远距离组成的序列记为{an},在{an}上选出一段连续区间[l,r],用e表示{al…r}的极差,满足e<=M,求出r-l+1的最大值。
首先注意这道题是连续的,我就被坑了;
首先可以知道要求离每个点的最远距离,可以暴力;
考虑优化,换根dp;
首先维护四个数组
\(f[u],fc[u],g[u],gc[u]\)
f分别表示以u为根的子树,u的最远距离;
和不重复的经过另一条边的最远距离;
g表示以u为起点,u的最远距离;
和不重复的经过另一条边的最远距离;
首先暴力算出以一为根的最远距离
然后换根,看代码
忘了,最后要求的是连续区间最大差值不超过m的;
可以同时用最大最小单调队列二维护;
#include <bits/stdc++.h>
using namespace std;
inline long long read() {
long long s = 0, f = 1; char ch;
while(!isdigit(ch = getchar())) (ch == '-') && (f = -f);
for(s = ch ^ 48;isdigit(ch = getchar()); s = (s << 1) + (s << 3) + (ch ^ 48));
return s * f;
}
const int N = 1e6 + 5;
int n, m, cnt, ans;
int head[N];
long long f[N], fc[N], g[N], gc[N], q1[N], q2[N];
struct edge {
int nxt, to, val;
} e[N << 1];
void add(int x, int y, int z) {
e[++cnt].nxt = head[x]; head[x] = cnt; e[cnt].to = y; e[cnt].val = z;
}
void dfs(int x, int fa) {
for(int i = head[x]; i ; i = e[i].nxt) {
int y = e[i].to; if(y == fa) continue;
dfs(y, x);
}
for(int i = head[x]; i ; i = e[i].nxt) {
int y = e[i].to; if(y == fa) continue;
if(f[x] < f[y] + e[i].val) {
fc[x] = f[x];
f[x] = max(f[x], f[y] + e[i].val);
}
else
if(fc[x] < f[y] + e[i].val) {
fc[x] = max(fc[x], f[y] + e[i].val);
}
}
}
void dfs2(int x, int fa, int w) {
if(x == 1) {
g[1] = f[1]; gc[1] = fc[1];
for(int i = head[x]; i ; i = e[i].nxt) {
int y = e[i].to; if(y == fa) continue;
else dfs2(y, x, e[i].val);
}
}
else {
if(f[x] + w != g[fa]) {
if(f[x] < w + g[fa]) {
g[x] = w + g[fa];
gc[x] = f[x];
}
else {
g[x] = f[x];
gc[x] = max(fc[x], w + g[fa]);
}
}
else {
if(f[x] < w + gc[fa]) {
g[x] = w + gc[fa];
gc[x] = f[x];
}
else {
g[x] = f[x];
gc[x] = max(fc[x], w + gc[fa]);
}
}
for(int i = head[x]; i ; i = e[i].nxt) {
int y = e[i].to; if(y == fa) continue;
else dfs2(y, x, e[i].val);
}
}
}
int main() {
// freopen("t3.in","r",stdin); freopen("t3.out","w",stdout);
n = read(); m = read();
for(int i = 2, x, y;i <= n; i++) {
x = read(); y = read();
add(i, x, y); add(x, i, y);
}
dfs(1, 0);
dfs2(1, 0, 0);
int l1 = 1, r1 = 0, l2 = 1, r2 = 0, t = 1;
// for(int i=1;i<=n;i++) cout<<g[i]<<"\n";
for(int i = 1;i <= n; i++)
{
while(l1 <= r1 && g[q1[r1]] <= g[i]) r1--;
q1[++r1] = i;
while(l2 <= r2 && g[q2[r2]] >= g[i]) r2--;
q2[++r2] = i;
while(g[q1[l1]] - g[q2[l2]] > m)
if(q1[l1] < q2[l2]) t = q1[l1] + 1, l1++;
else t = q2[l2] + 1, l2++;
ans = max(ans, i - t + 1);
}
printf("%d\n", ans);
// cout << endl;
// for(int i = 1;i <= n; i++) cout << i << ' ' << f[i] << " " << fc[i] << endl;
// cout << endl;
// for(int i = 1;i <= n; i++) cout << i << ' ' << g[i] << endl;
fclose(stdin); fclose(stdout);
return 0;
}
/*
3 2
1 1
1 3
*/