spoj 1825 Free tour II(树的点分治)

spoj 1825 Free tour II(树的点分治)

09年漆子超论文第二题。

主要是在算经过某一棵树的根的答案这一步很难想。假设这个根节点为u,有若干个子树v。f[i]表示已经当前要算的子树之前所有子树里面,最多经过i个黑点的最长路径是多少。这样的话,也就不难想出状态转移了。

细节有点多。。。。做得泪流满面

#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <map>
#include <queue>
#include <vector>
#include <string>
#include <iostream>
#define ll int
#define lson l , m , rt << 1
#define rson m + 1 , rt << 1 | 1
#define new_edge(a,b,c) edge[tot].t = b , edge[tot].v = c , edge[tot].next = head[a] , head[a] = tot ++
using namespace std;

const int maxn = 222222 ;

const int INF = -1111111111 ;
struct Edge {
    int t , next ;
    ll v ;
} edge[maxn<<1] ;
int head[maxn] , vis[maxn] , tot , k ;
int mark[maxn] ;

int temp , mdp[maxn] , dp[maxn] ;
ll que[maxn] , tail , ans , dis[maxn] , f[maxn] ;
int dep[maxn] , pos[maxn] ;

int cmp ( int a , int b ) {
    return dep[a] < dep[b] ;
}

int cnt_son ( int u , int fa ) {
    int i ;
    mdp[u] = dp[u] = 0 ;
    que[++tail] = u ;
    for ( i = head[u] ; i != -1 ; i = edge[i].next ) {
        int e = edge[i].t ;
        if ( e == fa || vis[e] ) continue ;
        cnt_son ( e , u ) ;
        dp[u] += dp[e] , mdp[u] = max ( mdp[u] , dp[e] ) ;
    }
    return ++ dp[u] ;
}

int get ( int u ) {
    int temp = maxn , ret ;
    tail = 0 ;
    cnt_son ( u , u ) ;
    while ( tail ) {
        int e = que[tail--] ;
        int fuck = max ( mdp[e] , dp[u] - dp[e] ) ;
        if ( fuck < temp ) temp = fuck , ret = e ;
    }
    return ret ;
}

void get_dep ( int u , int fa , int rt , int tot ) {
    int i ;
    dep[u] = mark[u] ;
    for ( i = head[u] ; i != -1 ; i = edge[i].next ) {
        int e = edge[i].t ;
        if ( e == fa || vis[e] ) continue ;
        get_dep ( e , u , rt , tot + mark[e] ) ;
        dep[u] = max ( dep[u] , dep[e] + mark[e] ) ;
    }
}

int lim ;
ll g[maxn] ;
void gao ( int u , int fa , int x , ll len , int rt ) {
    int i , j ;
    if ( x + mark[rt] <= k ) {
        g[x] = max ( g[x] , len ) ;
        ans = max ( ans , len + f[min(k-x-mark[rt],lim)] ) ;
    }
    for ( i = head[u] ; i != -1 ; i = edge[i].next ) {
        int e = edge[i].t ;
        if ( e == fa || vis[e] ) continue ;
        gao ( e , u , x + mark[e] , len + edge[i].v , rt ) ;
    }
}

void dfs ( int u ) {
    int cg = get ( u ) , i , j ;
    u = cg ;
    vis[u] = 1 ;
    tail = 0 ;
    for ( i = head[u] ; i != -1 ; i = edge[i].next ) {
        int e = edge[i].t ;
        if ( vis[e] ) continue ;
        pos[e] = edge[i].v ;
        que[++tail] = e ;
        get_dep ( e , e , e , mark[e] ) ;
    }
    sort ( que + 1 , que + tail + 1 , cmp ) ;
    for ( i = 0 ; i <= dep[que[tail]] ; i ++ ) f[i] = INF ;
    lim = 0 ;
    for ( i = 1 ; i <= tail ; i ++ ) {
        for ( j = 0 ; j <= dep[que[i]] ; j ++ ) g[j] = INF ;
        gao ( que[i] , que[i] , mark[que[i]] , pos[que[i]] , u ) ;
        lim = dep[que[i]] ;
        for ( j = 0 ; j <= dep[que[i]] ; j ++ ) {
            f[j] = max ( f[j] , g[j] ) ;
            if ( j ) f[j] = max ( f[j] , f[j-1] ) ;
            if ( i == 1 && j + mark[u] <= k ) ans = max ( ans , f[j] ) ;
        }
    }
    for ( i = head[u] ; i != -1 ; i = edge[i].next )
        if ( !vis[edge[i].t] ) dfs ( edge[i].t ) ;
}

void init () {
    memset ( head , -1 , sizeof ( head ) ) ;
    memset ( vis , 0 , sizeof ( vis ) ) ;
    memset ( mark , 0 , sizeof ( mark ) ) ;
    memset ( f , 0 , sizeof ( f ) ) ;
    tot = ans = 0 ;
}

int main() {
 //   freopen("E:/codeblock/test/a.txt","r",stdin);
 //   freopen("E:/codeblock/test/b.txt","w",stdout);
    int n , i , j , m ;
    while (scanf ( "%d%d%d" , &n , &k , &m ) != EOF ) {
    init () ;
    ans = 0 ;
    int a , b , c ;
    for ( i = 1 ; i <= m ; i ++ ) {
        scanf ( "%d" , &a ) ;
        mark[a] = 1 ;
    }
    for ( i = 1 ; i < n ; i ++ ) {
        scanf ( "%d%d%d" , &a , &b , &c ) ;
        new_edge ( a , b , c ) ;
        new_edge ( b , a , c ) ;
    }
    dfs ( 1 ) ;
    printf ( "%d\n" , ans ) ;
    }
    return 0;
}
/*
8 2 3
3
5
7
1 3 1
2 3 10
3 4 -2
4 5 -1
5 7 6
5 6 5
4 8 3

9 3 4
2
4
6
5
5 1 -5
8 9 5
9 5 2
2 4 -1
9 2 2
4 7 9
3 2 -4
6 9 6

6 3 5
1
5
3
6
2
5 2 8
3 4 3
6 4 8
3 2 7
3 1 2

10 1 3
6
8
1
9 4 -8
6 9 -9
2 9 -3
3 8 8
3 6 8
5 9 8
2 10 -2
4 1 8
8 7 -2
*/


你可能感兴趣的:(树分治)