bzoj2500幸福的道路 树形dp+单调队列
2500: 幸福的道路
Time Limit: 20 Sec Memory Limit: 256 MBSubmit: 434 Solved: 170
[Submit][Status][Discuss]
Description
小T与小L终于决定走在一起,他们不想浪费在一起的每一分每一秒,所以他们决定每天早上一同晨练来享受在一起的时光.
他们画出了晨练路线的草图,眼尖的小T发现可以用树来描绘这个草图.
他们不愿枯燥的每天从同一个地方开始他们的锻炼,所以他们准备给起点标号后顺序地从每个起点开始(第一天从起点一开始,第二天从起点二开始……). 而且他们给每条道路定上一个幸福的值.很显然他们每次出发都想走幸福值和最长的路线(即从起点到树上的某一点路径中最长的一条).
他们不愿再经历之前的大起大落,所以决定连续几天的幸福值波动不能超过M(即一段连续的区间并且区间的最大值最小值之差不超过M).他们想知道要是这样的话他们最多能连续锻炼多少天(hint:不一定从第一天一直开始连续锻炼)?
现在,他们把这个艰巨的任务交给你了!
Input
第一行包含两个整数N, M(M<=10^9).
第二至第N行,每行两个数字Fi , Di, 第i行表示第i个节点的父亲是Fi,且道路的幸福值是Di.
Output
最长的连续锻炼天数
Sample Input
3 2
1 1
1 3
1 1
1 3
Sample Output
3
数据范围:
50%的数据N<=1000
80%的数据N<=100 000
100%的数据N<=1000 000
数据范围:
50%的数据N<=1000
80%的数据N<=100 000
100%的数据N<=1000 000
这其实是两个题强行合在一起啊。。
首先是对于每个节点求它在树上的最长路,可以树形dp 2次,一次从儿子转移一次从父亲转移
求最长连续区间的话维护两个单调队列max min就好
1 #include<cstdio> 2 #include<iostream> 3 #include<algorithm> 4 #include<cstring> 5 #define N 1000005 6 #define ll long long 7 using namespace std; 8 int n,m,tot,w[N],hd[N],ans=1; 9 ll f[N],g[N],a[N];int mx[N],mn[N]; 10 struct edge{int v,w,next;}e[N<<1]; 11 char gc(){ 12 static char s[1000000],*p1,*p2; 13 if(p1==p2)p2=(p1=s)+fread(s,1,1000000,stdin); 14 if(p1==p2)return EOF; 15 return *p1++; 16 } 17 int read(){ 18 int x=0;char ch=gc(); 19 while(ch>'9'||ch<'0')ch=gc(); 20 while(ch<='9'&&ch>='0')x=x*10+ch-'0',ch=gc(); 21 return x; 22 } 23 void adde(int u,int v,int w){ 24 e[++tot].v=v; 25 e[tot].next=hd[u]; 26 e[tot].w=w; 27 hd[u]=tot; 28 } 29 void dfs1(int u,int fa){ 30 for(int i=hd[u];i;i=e[i].next){ 31 int v=e[i].v; 32 if(v==fa)continue; 33 dfs1(v,u); 34 f[u]=max(f[u],f[v]+e[i].w); 35 } 36 } 37 void dfs2(int u,int fa){ 38 ll mx1=0,mx2=0; 39 for(int i=hd[u];i;i=e[i].next){ 40 int v=e[i].v;if(v==fa)continue; 41 if(f[v]+e[i].w>mx1)mx2=mx1,mx1=f[v]+e[i].w; 42 else if(f[v]+e[i].w>mx2)mx2=f[v]+e[i].w; 43 g[v]=g[u]+e[i].w; 44 } 45 for(int i=hd[u];i;i=e[i].next){ 46 int v=e[i].v;if(v==fa)continue; 47 if(f[v]+e[i].w==mx1)g[v]=max(g[v],mx2+e[i].w); 48 else if(mx1+e[i].w>g[v])g[v]=mx1+e[i].w; 49 dfs2(v,u); 50 } 51 } 52 void solve(){ 53 for(register int i=1;i<=n;i++)a[i]=max(g[i],f[i]); 54 int l1=1,l2=1,r2=0,r1=0,t=1; 55 for(register int i=1;i<=n;i++){ 56 while(l1<=r1&&a[i]>=a[mx[r1]])r1--; 57 while(l2<=r2&&a[i]<=a[mn[r2]])r2--; 58 mx[++r1]=i;mn[++r2]=i; 59 while(a[mx[l1]]-a[mn[l2]]>m){ 60 if(mx[l1]<=mn[l2])t=mx[l1]+1,l1++; 61 else t=mn[l2]+1,l2++; 62 } 63 ans=max(ans,i-t+1); 64 } 65 } 66 int main(){ 67 n=read();m=read(); 68 for(register int i=2;i<=n;i++){ 69 int v=read(),w=read(); 70 adde(i,v,w);adde(v,i,w); 71 }dfs1(1,0);dfs2(1,0); 72 solve();printf("%d",ans); 73 return 0; 74 }
If you live in the echo,
your heart never beats as loud.
如果你生活在回声里,
你的心跳声永远不会轰鸣作响。