hdu 4123 Bob’s Race 树形DP + 单调队列

来源:互联网 发布:linux 打开一个目录 编辑:程序博客网 时间:2024/04/30 08:19

Bob’s Race

在昨天的模拟赛中,有一种情况没想明白,就没怎么写了。今天又想了一下,其实和hdu4008很像。然后重新写了一遍就AC了,看来树形DP的题目还得好好写写。

说一下思路:分为求每个点出发的最长路和求最长区间两个阶段。关于求最长区间的可以直接采用单调队列,hdu3530便是一个求最长区间的问题。主要说一下求每个点的出发的最长路。

求最长路:两个DFS. 第一次DFS,我们以任意一个点做为根节点,我采用的是编号为1的节点,求出每个节点在根为1的情况到叶子节点的最长距离和次长距离,要求次长距离与最长距离没有公共边。这里其实就是从节点x的子节点中选出路径最长的与路径次长的。这样就保证了没有公共边。

第二次DFS:变换根节点,也即旋转。将原先非根的节点变成根,当然这里只是为了求出该点出发的最长距离。我们设现在有节点v以及其子节点u.很容易知道经过v的最长路,肯定是从v的子节点走,或者从v的父节点(以第一次DFS的根节点为根的时候)。在算u的距离的时候,我们考虑:如果v的最长路径没有经过u,很显然此时u的最长距离肯定w(u , v) +v的最长距离;假设从u出发到叶子节点的最长距离为d[u] , 当v的最长路t[v] = d[u] + w(u , v) , 此时有可能有两条距离相等的最长路,或者最长路就只有经过u的路径。在前一种情况下,我们也很容易的算的t[u] = t[v] + w , 在后一种情况下,t[u]的值要么是d[u],要么是v的次长路径,不过次长路径是为经过u子树的。分析到这里,我们就知道需要求解出那些数据才能求解出每个点出发的最长距离。在第二次DFS的时候,我们同样的需要求出每个节点出发的最长路径与不相交的次长路径。关于次长路径的计算,参看程序中的解释。

/*author : csuchenanPROG   : hdu 4123LANG   : C++Algorithm : 树形DP + 单调队列17csu_chenan578MS3348K3690BC++2012-09-02 17:58:07*/#include <cstdio>#include <cstring>#include <vector>#define maxn 50005#define INF 100000000#define debug 0using std::vector ;struct node{    int f ;    int s ;    node(int a = 0 , int b = 0)    : f(a) , s(b){}};vector<node> G[maxn] ;int qmax[maxn] ;int qmin[maxn] ;int d[maxn][2] ;int t[maxn][2] ;int n ;int m ;int front ;int tail  ;int head  ;int rear  ;inline void init(){    memset(d , 0 , sizeof(d)) ;    memset(t , 0 , sizeof(t)) ;    for(int i = 0 ; i <= n ; i ++){        G[i].clear() ;    }}void swap(int &a , int &b){    a = a ^ b ;    b = a ^ b ;    a = a ^ b ;}int max(int x , int y){    return x > y ? x : y ;}void dfs1(int v , int fa){    //找出距离中最长的和次长的    for(vector<node>::size_type i = 0 ; i != G[v].size() ; i ++){        int u = G[v][i].f ;        int w = G[v][i].s ;        if(u==fa)            continue ;        dfs1(u , v) ;        if( d[u][0] + w > d[v][1] ){            d[v][1] = d[u][0] + w ;        }        if(d[v][1] > d[v][0]){            swap(d[v][1] , d[v][0]) ;        }    }}void dfs2(int v , int fa){    for(vector<node>::size_type i = 0 ; i != G[v].size() ; i ++){        int u = G[v][i].f ;        int w = G[v][i].s ;        if(u == fa)            continue ;        if(t[v][0] > d[u][0] + w){            //v的最长路不经过u点,            t[u][0] = t[v][0] + w ;            t[u][1] = d[u][0] ;        }        else{            //v的最长路可能经过u点的情况            if(t[v][1] == t[v][0]){                //v的次长路与最长路是相等的,                t[u][0] = t[v][0] + w ;                t[u][1] = d[u][0] ;            }            else{                //v的次长路与最长路不相等,必定经过u                if(t[v][1] + w >= d[u][0]){                    t[u][0] = t[v][1] + w ;                    t[u][1] = d[u][0] ;                }                else{                    t[u][0] = d[u][0] ;                    t[u][1] = max(t[v][1] + w , d[u][1]) ;                }            }        }        dfs2(u , v) ;    }}int work(int q){    int from = 1 ;    front = 1 ;    head  = 1 ;    tail  = 0 ;    rear  = 0 ;    int ans = 0 ;    for(int i = 1 ; i <= n ; i ++){        while(rear >= front && t[qmax[rear]][0] < t[i][0])            rear -- ;        qmax[++ rear] = i ;        while(tail >= head && t[qmin[tail]][0] > t[i][0])            tail -- ;        qmin[++ tail] = i ;        if(t[qmax[front]][0] - t[qmin[head]][0] > q){            if(qmax[front] < qmin[head]){                from = qmax[front] + 1 ;                front ++ ;            }            else{                from = qmin[head] + 1 ;                head ++ ;            }        }        if(ans < i - from + 1)            ans = i - from + 1 ;    }    return ans ;}void solve(){    dfs1(1 , 0) ;    t[1][0] = d[1][0] ;    t[1][1] = d[1][1] ;    dfs2(1 , 0) ;    if(debug){        for(int i = 1 ; i <= n ; i ++){            printf("%d %d %d\n" , i , t[i][0] , d[i][0]) ;        }    }    int q ;    int ans ;    for(int i = 0 ; i < m ; i ++){        scanf("%d" , &q) ;        ans = work(q) ;        printf("%d\n" , ans) ;    }}int main(){    while(scanf("%d%d" , &n , &m) , n||m){        int a ;        int b ;        int c ;        init() ;        for(int i = 1 ; i < n ; i ++){            scanf("%d%d%d" , &a , &b , &c) ;            G[a].push_back(node(b , c)) ;            G[b].push_back(node(a , c)) ;        }        solve() ;    }    return 0 ;}







原创粉丝点击