POJ 3162 Walking Race(树形dp+单调队列 or 线段树)
http://poj.org/problem?id=3162
题意:
一棵n个节点的树。有一个屌丝爱跑步,跑n天,第i天从第i个节点开始跑步,每次跑到距第i个节点最远的那个节点(产生了n个距离),现在要在这n个距离里取连续的若干天,使得这些天里最大距离和最小距离的差小于M,问怎么取使得天数最多?
思路:
这道题目求最远距离和HDU 2196是一模一样的,这个不是很难。关键是要怎么处理得到的数据。
可以用单调队列做也可以用线段树来做,先介绍一下单调队列。
因为有最大值和最小值,所以我们需要两个单调队列,一个维护最大值,另一个维护最小值。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include<iostream> 2 #include<algorithm> 3 #include<cstring> 4 #include<cstdio> 5 #include<sstream> 6 #include<vector> 7 #include<stack> 8 #include<queue> 9 #include<cmath> 10 #include<map> 11 #include<set> 12 using namespace std; 13 typedef long long ll; 14 typedef pair<int,ll> pll; 15 const int INF = 0x3f3f3f3f; 16 const int maxn=1e6+5; 17 18 int n, m; 19 int tot; 20 ll d[maxn][3]; 21 int path[maxn]; 22 int head[2*maxn]; 23 int q_max[maxn]; 24 int q_min[maxn]; 25 26 struct node 27 { 28 int v,w,next; 29 }e[2*maxn]; 30 31 void addEdge(int u,int v,int w) 32 { 33 e[tot].v=v; 34 e[tot].w=w; 35 e[tot].next=head[u]; 36 head[u]=tot++; 37 } 38 39 void dfs1(int u,int fa) 40 { 41 d[u][0]=d[u][1]=0; 42 path[u]=-1; 43 for(int i=head[u];i!=-1;i=e[i].next) 44 { 45 int v=e[i].v; 46 if(v==fa) continue; 47 dfs1(v,u); 48 if(d[u][0]<d[v][0]+e[i].w) 49 { 50 path[u]=v; 51 d[u][1]=d[u][0]; 52 d[u][0]=d[v][0]+e[i].w; 53 } 54 else if(d[u][1]<d[v][0]+e[i].w) 55 d[u][1]=d[v][0]+e[i].w; 56 } 57 } 58 59 void dfs2(int u,int fa) 60 { 61 for(int i=head[u];i!=-1;i=e[i].next) 62 { 63 int v=e[i].v; 64 if(v==fa) continue; 65 if(path[u]==v) d[v][2]=max(d[u][2],d[u][1])+e[i].w; 66 else d[v][2]=max(d[u][0],d[u][2])+e[i].w; 67 dfs2(v,u); 68 } 69 } 70 71 int main() 72 { 73 //freopen("in.txt","r",stdin); 74 while(~scanf("%d%d",&n,&m)) 75 { 76 tot=0; 77 memset(head,-1,sizeof(head)); 78 for(int i=2;i<=n;i++) 79 { 80 int v,w; 81 scanf("%d%d",&v,&w); 82 addEdge(i,v,w); 83 addEdge(v,i,w); 84 } 85 dfs1(1,-1); 86 dfs2(1,-1); 87 int ans=-1; 88 int frt_max=1,rear_max=1; 89 int frt_min=1,rear_min=1; 90 for(int i=1,j=1;i<=n;i++) 91 { 92 d[i][0]=max(d[i][0],d[i][2]); 93 while(frt_max<rear_max && d[q_max[rear_max-1]][0]<d[i][0]) rear_max--; 94 q_max[rear_max++]=i; 95 while(frt_min<rear_min && d[q_min[rear_min-1]][0]>d[i][0]) rear_min--; 96 q_min[rear_min++]=i; 97 98 while(frt_max<rear_max && frt_min<rear_min && d[q_max[frt_max]][0]-d[q_min[frt_min]][0]>m) 99 { 100 if(q_max[frt_max]>q_min[frt_min]) {j=q_min[frt_min]+1;frt_min++;} 101 else {j=q_max[frt_max]+1;frt_max++;} 102 } 103 ans=max(ans,i-j+1); 104 } 105 printf("%d\n",ans); 106 } 107 return 0; 108 }
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include<iostream> 2 #include<algorithm> 3 #include<cstring> 4 #include<cstdio> 5 #include<sstream> 6 #include<vector> 7 #include<stack> 8 #include<queue> 9 #include<cmath> 10 #include<map> 11 #include<set> 12 using namespace std; 13 typedef long long ll; 14 typedef pair<int,ll> pll; 15 const int INF = 0x3f3f3f3f; 16 const int maxn=1e6+5; 17 18 int n, m; 19 int tot; 20 ll d[maxn][3]; 21 int path[maxn]; 22 int head[2*maxn]; 23 24 int MAX[maxn<<2]; 25 int MIN[maxn<<2]; 26 int query_max,query_min; 27 28 struct node 29 { 30 int v,w,next; 31 }e[2*maxn]; 32 33 void addEdge(int u,int v,int w) 34 { 35 e[tot].v=v; 36 e[tot].w=w; 37 e[tot].next=head[u]; 38 head[u]=tot++; 39 } 40 41 /********************************************** 42 dfs 43 **********************************************/ 44 45 void dfs1(int u,int fa) 46 { 47 d[u][0]=d[u][1]=0; 48 path[u]=-1; 49 for(int i=head[u];i!=-1;i=e[i].next) 50 { 51 int v=e[i].v; 52 if(v==fa) continue; 53 dfs1(v,u); 54 if(d[u][0]<d[v][0]+e[i].w) 55 { 56 path[u]=v; 57 d[u][1]=d[u][0]; 58 d[u][0]=d[v][0]+e[i].w; 59 } 60 else if(d[u][1]<d[v][0]+e[i].w) 61 d[u][1]=d[v][0]+e[i].w; 62 } 63 } 64 65 void dfs2(int u,int fa) 66 { 67 for(int i=head[u];i!=-1;i=e[i].next) 68 { 69 int v=e[i].v; 70 if(v==fa) continue; 71 if(path[u]==v) d[v][2]=max(d[u][2],d[u][1])+e[i].w; 72 else d[v][2]=max(d[u][0],d[u][2])+e[i].w; 73 dfs2(v,u); 74 } 75 } 76 77 /********************************************** 78 线段树 79 **********************************************/ 80 81 void PushUp(int o) 82 { 83 MAX[o]=max(MAX[o<<1],MAX[o<<1|1]); 84 MIN[o]=min(MIN[o<<1],MIN[o<<1|1]); 85 } 86 87 void build(int l, int r, int o) 88 { 89 if(l==r) 90 { 91 MAX[o]=MIN[o]=max(d[l][0],d[l][2]); 92 return; 93 } 94 int mid=(l+r)/2; 95 build(l,mid,o<<1); 96 build(mid+1,r,o<<1|1); 97 PushUp(o); 98 } 99 100 void query(int ql, int qr, int l, int r, int o) 101 { 102 if(ql<=l && qr>=r) 103 { 104 query_max=max(query_max,MAX[o]); 105 query_min=min(query_min,MIN[o]); 106 return; 107 } 108 int mid=(l+r)/2; 109 if(ql<=mid) query(ql,qr,l,mid,o<<1); 110 if(mid<qr) query(ql,qr,mid+1,r,o<<1|1); 111 } 112 113 int main() 114 { 115 //freopen("in.txt","r",stdin); 116 while(~scanf("%d%d",&n,&m)) 117 { 118 tot=0; 119 memset(head,-1,sizeof(head)); 120 for(int i=2;i<=n;i++) 121 { 122 int v,w; 123 scanf("%d%d",&v,&w); 124 addEdge(i,v,w); 125 addEdge(v,i,w); 126 } 127 dfs1(1,-1); 128 dfs2(1,-1); 129 build(1,n,1); 130 int ans=0; 131 132 int l=1,r=1; 133 while(r<=n) 134 { 135 query_max=0; query_min=INF; 136 query(l,r,1,n,1); 137 if(query_max-query_min<=m) {ans=max(ans,r-l+1);r++;} 138 while(query_max-query_min>m) 139 { 140 l++; 141 query_max=0; query_min=INF; 142 query(l,r,1,n,1); 143 } 144 } 145 printf("%d\n",ans); 146 } 147 return 0; 148 }