题目链接:微软员工的福利(中等)
题意是………………题面描述的那样…..中文题.
我只想到了中等的解法,就是对于一个点直接枚举他儿子和他自己的两个最值,然后树型dp,复杂度是O(n³),思路比较清晰但是写起代码来比较复杂,因为在枚举最大值最小值的时候要考虑到这个最值是不是该点他本身.
#include<cmath>
#include<algorithm>
#include<cstring>
#include<string>
#include<set>
#include<map>
#include<time.h>
#include<cstdio>
#include<vector>
#include<list>
#include<stack>
#include<queue>
#include<iostream>
#include<stdlib.h>
using namespace std;
#define LONG long long
const LONG INF = 0x3f3f3f3f;
const LONG MOD = 1e9+ 7;
const double PI = acos(-1.0);
#define clrI(x) memset(x,-1,sizeof(x))
#define clr0(x) memset(x,0,sizeof x)
#define clr1(x) memset(x,INF,sizeof x)
#define clr2(x) memset(x,-INF,sizeof x)
#define EPS 1e-10
#define lson l , mid , rt<< 1
#define rson mid + 1 ,r , (rt<<1)+1
#define root 1, m , 1
struct Edge
{
LONG to ,next , u ;
}edge[500] ;
LONG tot = 0 ;
LONG head[500 ] ;
LONG R[400 ] ;
LONG P[400 ] ;
LONG dp[400][2] ;
LONG son[400] ;
void Init()
{
tot =0 ;
clrI(head) ;
clr0(dp) ;
}
void Add_edge(LONG u , LONG v )
{
edge[++tot].to = v ;
edge[tot].next = head[u] ;
edge[tot].u = u ;
head[u] = tot ;
}
void dfs(LONG pre , LONG u )
{
LONG p = 0;
for(LONG i = head[u] ; ~i ; i =edge[i].next)
{
LONG v = edge[i].to ;
if(v == pre) continue;
dfs(u , v) ;
}
son[++p] = u ;
for(LONG i = head[u] ; ~i ; i =edge[i].next)
{
LONG v = edge[i].to ;
if(v == pre) continue ;
son[++p] = v ;
}
;
if(p == 1)
{
dp[u][0] = P[u] ;
dp[u][1] = R[u] ;
return ;
}
if(p == 2)
{
LONG t = son[2] ;
LONG r1 = abs(R[t] - P[u]) ;
LONG r2 = abs(P[t] - P[u]) ;
dp[u][0] = max( -(r1 + 999) / 1000 * 666 * u + P[u] + dp[t][1] , -(r2 + 999) / 1000 * 666 * u + P[u] + dp[t][0] ) ;
r1 = abs(R[t] - R[u]) ;
r2 = abs(P[t] - R[u]) ;
dp[u][1] = max(-(r1 + 999)/1000 * 666 * u + R[u] + dp[t][1] , -(r2+ 999) / 1000 * 666 * u + R[u] + dp[t][0]) ;
return ;
}
dp[u][0] = -1e15 ;
dp[u][1] = -1e15 ;
for(LONG _ii = 0 ; _ii <= 1 ; _ii ++ ){
LONG res = -1e15 ;
LONG tag ;
if(_ii == 0) tag = P[u] ;
else tag = R[u] ;
for(LONG i = 2 ; i <= p ; ++ i)
{
for(LONG j = 2 ; j <= p ; ++j)
{
if(i == j) continue ;
LONG maxn , minx ;
//
for(LONG _tt = 1 ; _tt <= 4 ;++ _tt){
LONG x = son[i] , y = son[j] ;
if(_tt == 1)
maxn = P[x] ,minx = P[y] ;
else if(_tt == 2)
maxn = P[x] , minx = R[y] ;
else if(_tt == 3)
maxn = R[x] , minx = P[y] ;
else
maxn = R[x] ,minx = R[y] ;
if(tag > maxn ) maxn = tag , x = 0 ;
if(tag < minx ) minx = tag ,y = 0 ;
if(maxn < minx ) continue ;
LONG judge = 1;
for(LONG k = 2 ; k <= p ; ++k)
{
LONG t = son[k] ;
if(R[t] >= minx && R[t] <= maxn ||P[t] >=minx &&P[t] <=maxn )
{}
else
{
judge = 0 ;break ;
}
}
if(judge )
{
LONG temp ;
if(_tt == 1)
temp = dp[x][0] + dp[y][0] ;
else if(_tt == 2)
temp = dp[x][0] +dp[y][1] ;
else if(_tt == 3)
temp = dp[x][1] +dp[y][0] ;
else
temp = dp[x][1] + dp[y][1] ;
LONG tmp = temp - (maxn - minx + 999 ) / 1000 * 666 * u;
for(LONG k = 2 ; k <= p ; ++k)
{
LONG t = son[k] ;
if(t == x || t == y) continue ;
if(R[t] <=maxn && P[t] <= maxn && R[t] >= minx && P[t] >= minx )
tmp += max( dp[t][0] , dp[t][1]) ;
else if( P[t ] <= maxn && P[t] >= minx )
tmp += dp[t][0] ;
else tmp += dp[t][1] ;
}
tmp += tag ;
if(_ii == 0)
dp[u][0] = max(dp[u][0] , tmp ) ;
else dp[u][1] = max(dp[u][1] , tmp) ;
}
}
}
}
}
}
int main()
{
Init() ;
LONG n ;
cin >>n ;
LONG u , v;
for(LONG i =1; i<= n ;++ i)
scanf("%lld%lld" ,&R[i] , &P[i]) ;
for(LONG i = 1 ;i < n ; ++i)
{
scanf("%lld%lld",&u,&v ) ;
Add_edge(u , v ) ;
Add_edge(v , u ) ;
}
dfs(-1 , 1) ;
printf("%lld\n",max(dp[1][0],dp[1][1]));
return 0 ;
}