bzoj 2500: 幸福的道路 动态规划+单调栈

来源:互联网 发布:打电话变声软件下载 编辑:程序博客网 时间:2024/05/28 05:14

题意

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

分析

首先我们要把点权求出来。
那么我们设1为根节点,用两个数组fir[i]和sec[i]维护从节点i开始最长的路径和次长的路径。
第一次先求出起点为i终点在i的子树内的最长路和次长路,第二次再求出每个节点往其父节点走的最长路径。
接着就要求最大的区间,这里我一开始的想法是用数据结构来维护,set或者线段树什么的应该都行,但是我们注意到n<=1000000,则这么干有可能会超时。
那么我们就改用单调栈来维护最大值和最小值。
第一个单调栈保证里面的元素严格递增,第二个单调栈保证里面的元素严格递减,那么最大值就是第二个单调栈的栈底,最小值就是第一个单调栈的栈顶,我们只需要每次插入i时同时维护这两个单调栈即可。

1A大法好!!!

代码

#include<iostream>#include<cstdio>#include<cstdlib>#include<cstring>#include<algorithm>#define N 1000005using namespace std;int n,m,last[N],cnt;struct edge{int to,len,next;}e[N*2];struct stack{int len,id;}stack1[N],stack2[N];struct data{int num,len;}fir[N],sec[N];void addedge(int u,int v,int len){    e[++cnt].to=v;e[cnt].len=len;e[cnt].next=last[u];last[u]=cnt;    e[++cnt].to=u;e[cnt].len=len;e[cnt].next=last[v];last[v]=cnt;}void dfs1(int x,int fa){    for (int i=last[x];i;i=e[i].next)    {        if (e[i].to==fa) continue;        dfs1(e[i].to,x);        if (fir[e[i].to].len+e[i].len>fir[x].len)        {            sec[x]=fir[x];            fir[x].len=fir[e[i].to].len+e[i].len;            fir[x].num=e[i].to;        }else if (fir[e[i].to].len+e[i].len>sec[x].len)        {            sec[x].len=fir[e[i].to].len+e[i].len;            sec[x].num=e[i].to;        }    }}void dfs2(int x,int fa,int len){    int w;    if (fir[fa].num==x) w=sec[fa].len+len;    else w=fir[fa].len+len;    if (w>fir[x].len)    {        sec[x]=fir[x];        fir[x].len=w;        fir[x].num=fa;    }else if (w>sec[x].len)    {        sec[x].len=w;        sec[x].num=fa;    }    for (int i=last[x];i;i=e[i].next)    {        if (e[i].to==fa) continue;        dfs2(e[i].to,x,e[i].len);    }}int main(){    scanf("%d%d",&n,&m);    for (int i=2;i<=n;i++)    {        int x,y;        scanf("%d%d",&x,&y);        addedge(x,i,y);    }    dfs1(1,0);    dfs2(1,0,0);    int head1=1,tail1=0,head2=1,tail2=0,l=1,ans=0;    for (int i=1;i<=n;i++)    {        int w=fir[i].len;        while (head1<=tail1&&stack1[tail1].len>=w) tail1--;        tail1++;        stack1[tail1].len=w;        stack1[tail1].id=i;        while (head2<=tail2&&stack2[tail2].len<=w) tail2--;        tail2++;        stack2[tail2].len=w;        stack2[tail2].id=i;        while (stack2[head2].len-stack1[head1].len>m)            if (stack1[head1].id<stack2[head2].id)            {                l=stack1[head1].id+1;                head1++;            }else            {                l=stack2[head2].id+1;                head2++;            }        ans=max(ans,i-l+1);    }    printf("%d",ans);    return 0;}
2 0
原创粉丝点击