幸福的道路(race) ssl 2570 bzoj 2500 单调队列

来源:互联网 发布:支持绑定第三方域名 编辑:程序博客网 时间:2024/05/19 19:15

题目大意

给出一棵树,每条边都有一个长度。我们规定每个点的权值为从该点开始走过的一条最长的路径的长度。
求一个最长的区间[l,r],使得[l,r]里面点权的最大值和最小值只差不超过m。
n<=1000000

分析

用两个dfs求出一个点向上和向下可以走的最长路。
(可以设f[i][1],f[i][2],f[i][3],分别表示i到叶子的最长链,i到叶子的次长链,从i向上走到某个父亲,再向下的最长链。)
那更新就是….,很容易的啦233

那么我们现在就得到了a[i]=max(f[i][1],f[i][3])表示从i出发的最长链的长度。

第二步是要在a数组中求一段最长的区间满足极差小于等于m。

用两个队列分别维护最大值和最小值,将当前结点入队后,如果最大值-最小值(两个队列的队头)>m,则选一个较小的队头,以i为右节点的最长区间的左端点,就是较小的队头表示的位置+1,扔掉那个最小的以后继续扔,边扔边更新答案,扔到合法为止)

ps:bzoj现在这道题用不了啊

code

#include<iostream>#include<cstring>#include<cstdio>#include<cmath>#include<string>#include<algorithm>using namespace std;int f[2000000][5];int a[2000000][5];int ls[2000000];struct arr{    int x,y,w;    int next;}c[2000000];int head[2],tail[2];int n,m,nn;int add(int x,int y,int w){    nn++;    c[nn].x=x;    c[nn].y=y;    c[nn].w=w;    c[nn].next=ls[x];    ls[x]=nn;}int dfs1(int x,int r){    int i=ls[x];    while (i!=0)    {        dfs1(c[i].y,x);        if (a[x][0]<a[c[i].y][0]+c[i].w)            a[x][1]=a[x][0],a[x][0]=a[c[i].y][0]+c[i].w;        else            if (a[x][1]<a[c[i].y][0]+c[i].w)                a[x][1]=a[c[i].y][0]+c[i].w;        i=c[i].next;    }}int dfs2(int x,int r,int w){    int max1=a[r][0];    if (a[x][0]+w==a[r][0])        max1=a[r][1];    a[x][2]=max(max1,a[r][2])+w;    int i=ls[x];    while (i!=0)    {        dfs2(c[i].y,x,c[i].w);        i=c[i].next;    }}int main(){    scanf("%d%d",&n,&m);    for (int i=2;i<=n;i++)    {        int x=0;        int w=0;        scanf("%d%d",&x,&w);        add(x,i,w);    }    dfs1(1,0);    dfs2(1,0,0);    head[0]=head[1]=1;    tail[0]=tail[1]=0;    int ans=0;    int l=1;    for (int i=1;i<=n;i++)    {        int max1;        max1=max(a[i][0],a[i][2]);        a[i][3]=max1;        while ((a[f[tail[0]][0]][3]<=max1)&&(head[0]<=tail[0]))            tail[0]--;        while ((a[f[tail[1]][1]][3]>=max1)&&(head[1]<=tail[1]))            tail[1]--;        tail[0]++;        f[tail[0]][0]=i;        tail[1]++;        f[tail[1]][1]=i;        while (a[f[head[0]][0]][3]-a[f[head[1]][1]][3]>m)        {            if (f[head[0]][0]>f[head[1]][1])                l=f[head[1]][1]+1,head[1]++;            else                l=f[head[0]][0]+1,head[0]++;        }        ans=max(ans,i-l+1);    }    printf("%d",ans);}
1 0