POJ3162 Walking Race(树形DP+尺取法+单调队列)
题目大概是给一棵n个结点边带权的树,记结点i到其他结点最远距离为d[i],问d数组构成的这个序列中满足其中最大值与最小值的差不超过m的连续子序列最长是多长。
各个结点到其他结点的最远距离可以用树形DP解决,HDU2196。
而那个最长的连续子序列可以用单调队列求。。搞了挺久看了解法体会了下。。简单来说就是尺取法,用两个指针[i,j]表示区间,j不停+1往前移动,然后用两个单调队列分别同时更新区间最小值和最大值,再看两个队列队首的最值差是否大于m,是的话出队并调整i值,最后用j-i+1更新答案。
当然尺取法+RMQ也是OK的。
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 using namespace std; 5 #define INF (1LL<<60) 6 #define MAXN 1000111 7 struct Edge{ 8 int v,w,next; 9 }edge[MAXN]; 10 int NE,head[MAXN]; 11 void addEdge(int u,int v,int w){ 12 edge[NE].v=v; edge[NE].w=w; edge[NE].next=head[u]; 13 head[u]=NE++; 14 } 15 int idx[MAXN]; 16 long long d[3][MAXN]; 17 void dp0(int u){ 18 for(int i=head[u]; i!=-1; i=edge[i].next){ 19 int v=edge[i].v; 20 dp0(v); 21 if(d[0][u]<=d[0][v]+edge[i].w){ 22 d[1][u]=d[0][u]; 23 d[0][u]=d[0][v]+edge[i].w; 24 idx[u]=v; 25 }else if(d[1][u]<d[0][v]+edge[i].w){ 26 d[1][u]=d[0][v]+edge[i].w; 27 }else if(d[1][u]<d[1][v]+edge[i].w){ 28 d[1][u]=d[1][v]+edge[i].w; 29 } 30 } 31 } 32 void dp1(int u){ 33 for(int i=head[u]; i!=-1; i=edge[i].next){ 34 int v=edge[i].v; 35 if(idx[u]==v) d[2][v]=max(d[1][u],d[2][u])+edge[i].w; 36 else d[2][v]=max(d[0][u],d[2][u])+edge[i].w; 37 dp1(v); 38 } 39 } 40 struct Que{ 41 int que[MAXN],front,rear; 42 bool isEmpty(){ 43 return front==rear; 44 } 45 int getFront(){ 46 return que[front]; 47 } 48 int getRear(){ 49 return que[rear-1]; 50 } 51 void push(int a){ 52 que[rear++]=a; 53 } 54 }mxq,mmq; 55 int main(){ 56 memset(head,-1,sizeof(head)); 57 int n,m,a,b; 58 scanf("%d%d",&n,&m); 59 for(int i=2; i<=n; ++i){ 60 scanf("%d%d",&a,&b); 61 addEdge(a,i,b); 62 } 63 dp0(1); 64 dp1(1); 65 int res=0; 66 for(int i=1,j=1; i<=n; ++i){ 67 d[0][i]=max(d[0][i],d[2][i]); 68 while(!mxq.isEmpty() && d[0][mxq.getRear()]<d[0][i]) --mxq.rear; 69 mxq.push(i); 70 while(!mmq.isEmpty() && d[0][mmq.getRear()]>d[0][i]) --mmq.rear; 71 mmq.push(i); 72 while(d[0][mxq.getFront()]-d[0][mmq.getFront()]>m){ 73 if(mxq.getFront()<mmq.getFront()) j=mxq.getFront()+1,++mxq.front; 74 else j=mmq.getFront()+1,++mmq.front; 75 } 76 res=max(res,i-j+1); 77 } 78 printf("%d",res); 79 return 0; 80 }