传送门:【HDU】5052 Yaoge’s maximum profit
题目分析:别人用LCT过的。。Orz。。
我是比赛的时候第一道看的就是这题。。然后觉得可做。。。然后就去做别的题了。。到最后才回来做这道题,可笑的是到最后竟然没有AC。。吃了晚饭以后发现漏考虑了情况,回来改了改。。不到一分钟时间,AC了。。。。。。
现在说一下我的做法。
还是老方法,假设这只是一个区间而不是一棵树,那我们怎么解决?
考虑到是右边的最大值减去左边的最小值,我们可以给每个区间三个标记,区间最大值maxv,区间最小值minv,区间内最优的最大值减去最小值的值best。更新的时候只会修改最大值以及最小值,维护的时候也很简单。显然我们要解决的问题就是查询,对于区间【L,R】,如果【L,R】可以被分成【L,m】【m+1,R】,那么显然【L,R】的最优值就是:max(max(best[ls],best[rs]),max[rs]-min[ls])。
按照这个方法不断往上合并结果,就能得到查询区间的最优值best。
现在我们的问题是一棵树,显然我们可以将问题转化为一条链上,多个区间的子问题。
首先我们做树链剖分。
然后我们需要维护四个标记,maxv,minv,从左到右的最优值best[0],从右到左的最优值best[1],为什么多了个从右到左的标记?如果查询是X->Y,因为树链剖分过程中从X到lca(X,Y)的路上的局部最优值的查询是和路径方向相反的!所以我们还需要维护相反方向的best值。
在树链剖分的查询过程中,我们还需要维护这条链从X到lca的路上的最小值Min,以及从Y到lca的路上的最大值Max,同时不断用这两个变量更新结果。
最后我们就能得到需要的结果了~
犯的错误:
思考不仔细,没有所有情况都马上考虑到
代码如下:
#include <cstdio> #include <cstring> #include <algorithm> #include <cmath> using namespace std ; typedef long long LL ; #define rep( i , a , b ) for ( int i = a ; i < b ; ++ i ) #define For( i , a , b ) for ( int i = a ; i <= b ; ++ i ) #define rev( i , a , b ) for ( int i = a ; i >= b ; -- i ) #define travel( e , H , u ) for ( Edge* e = H[u] ; e ; e = e -> next ) #define clr( a , x ) memset ( a , x , sizeof a ) #define cpy( a , x ) memcpy ( a , x , sizeof a ) #define ls ( o << 1 ) #define rs ( o << 1 | 1 ) #define lson ls , l , m #define rson rs , m + 1 , r #define mid ( ( l + r ) >> 1 ) #define root 1 , 1 , n const int MAXN = 50005 ; const int MAXE = 100005 ; const int INF = 0x3f3f3f3f ; struct Edge { int v ; Edge* next ; } E[MAXE] , *H[MAXN] , *edge ; int siz[MAXN] ; int top[MAXN] ; int pre[MAXN] ; int pos[MAXN] ; int dep[MAXN] ; int son[MAXN] ; int idx[MAXN] ; int val[MAXN] ; int minv[MAXN << 2] ; int maxv[MAXN << 2] ; int addv[MAXN << 2] ; int best[2][MAXN << 2] ; int tree_idx ; int n , q ; void clear () { edge = E ; tree_idx = 0 ; pre[1] = 0 ; siz[0] = 0 ; clr ( H , 0 ) ; } void addedge ( int u , int v ) { edge -> v = v ; edge -> next = H[u] ; H[u] = edge ++ ; } void dfs ( int u ) { siz[u] = 1 ; son[u] = 0 ; travel ( e , H , u ) { int v = e -> v ; if ( v != pre[u] ) { pre[v] = u ; dep[v] = dep[u] + 1 ; dfs ( v ) ; siz[u] += siz[v] ; if ( siz[v] > siz[son[u]] ) son[u] = v ; } } } void rewrite ( int u , int top_element ) { top[u] = top_element ; pos[u] = ++ tree_idx ; idx[tree_idx] = u ; if ( son[u] ) rewrite ( son[u] , top_element ) ; travel ( e , H , u ) { int v = e -> v ; if ( v != son[u] && v != pre[u]) rewrite ( v , v ) ; } } void pushup ( int o ) { maxv[o] = max ( maxv[ls] , maxv[rs] ) ; minv[o] = min ( minv[ls] , minv[rs] ) ; best[0][o] = max ( best[0][ls] , best[0][rs] ) ; best[0][o] = max ( best[0][o] , maxv[rs] - minv[ls] ) ; best[1][o] = max ( best[1][ls] , best[1][rs] ) ; best[1][o] = max ( best[1][o] , maxv[ls] - minv[rs] ) ; } void pushdown ( int o ) { if ( addv[o] ) { addv[ls] += addv[o] ; addv[rs] += addv[o] ; minv[ls] += addv[o] ; minv[rs] += addv[o] ; maxv[ls] += addv[o] ; maxv[rs] += addv[o] ; addv[o] = 0 ; } } void sub_update ( int L , int R , int v , int o , int l , int r ) { if ( L <= l && r <= R ) { minv[o] += v ; maxv[o] += v ; addv[o] += v ; return ; } int m = mid ; pushdown ( o ) ; if ( L <= m ) sub_update ( L , R , v , lson ) ; if ( m < R ) sub_update ( L , R , v , rson ) ; pushup ( o ) ; } void update ( int x , int y , int v ) { while ( top[x] != top[y] ) { if ( dep[top[x]] < dep[top[y]] ) swap ( x , y ) ; sub_update ( pos[top[x]] , pos[x] , v , root ) ; x = pre[top[x]] ; } if ( dep[x] > dep[y] ) sub_update ( pos[y] , pos[x] , v , root ) ; else sub_update ( pos[x] , pos[y] , v , root ) ; } int query_min ( int L , int R , int o , int l , int r ) { if ( L <= l && r <= R ) return minv[o] ; int m = mid ; pushdown ( o ) ; if ( R <= m ) return query_min ( L , R , lson ) ; if ( m < L ) return query_min ( L , R , rson ) ; return min ( query_min ( L , R , lson ) , query_min ( L , R , rson ) ) ; } int query_max ( int L , int R , int o , int l , int r ) { if ( L <= l && r <= R ) return maxv[o] ; int m = mid ; pushdown ( o ) ; if ( R <= m ) return query_max ( L , R , lson ) ; if ( m < L ) return query_max ( L , R , rson ) ; return max ( query_max ( L , R , lson ) , query_max ( L , R , rson ) ) ; } int query_best ( int L , int R , int x , int o , int l , int r ) { if ( L <= l && r <= R ) return best[x][o] ; int m = mid ; pushdown ( o ) ; if ( R <= m ) return query_best ( L , R , x , lson ) ; if ( m < L ) return query_best ( L , R , x , rson ) ; int ans = max ( query_best ( L , R , x , lson ) , query_best ( L , R , x , rson ) ) ; if ( !x ) ans = max ( ans , query_max ( L , R , rson ) - query_min ( L , R , lson ) ) ; else ans = max ( ans , query_max ( L , R , lson ) - query_min ( L , R , rson ) ) ; return ans ; } int query ( int x , int y ) { int Min = INF , Max = -INF ; int ans = 0 ; while ( top[x] != top[y] ) { if ( dep[top[x]] > dep[top[y]] ) { ans = max ( ans , query_max ( pos[top[x]] , pos[x] , root ) - Min ) ; Min = min ( Min , query_min ( pos[top[x]] , pos[x] , root ) ) ; ans = max ( ans , query_best ( pos[top[x]] , pos[x] , 1 , root ) ) ; x = pre[top[x]] ; } else { ans = max ( ans , Max - query_min ( pos[top[y]] , pos[y] , root ) ) ; Max = max ( Max , query_max ( pos[top[y]] , pos[y] , root ) ) ; ans = max ( ans , query_best ( pos[top[y]] , pos[y] , 0 , root ) ) ; y = pre[top[y]] ; } } ans = max ( ans , Max - Min ) ; if ( dep[x] < dep[y] ) { ans = max ( ans , query_best ( pos[x] , pos[y] , 0 , root ) ) ; ans = max ( ans , query_max ( pos[x] , pos[y] , root ) - Min ) ; ans = max ( ans , Max - query_min ( pos[x] , pos[y] , root ) ) ; } else { ans = max ( ans , query_best ( pos[y] , pos[x] , 1 , root ) ) ; ans = max ( ans , query_max ( pos[y] , pos[x] , root ) - Min ) ; ans = max ( ans , Max - query_min ( pos[y] , pos[x] , root ) ) ; } return ans ; } void scanf ( int& x , char c = 0 ) { while ( ( c = getchar () ) < '0' || c > '9' ) ; x = c - '0' ; while ( ( c = getchar () ) >= '0' && c <= '9' ) x = x * 10 + c - '0' ; } void build ( int o , int l , int r ) { addv[o] = 0 ; if ( l == r ) { best[0][o] = best[1][o] = 0 ; maxv[o] = minv[o] = val[idx[l]] ; return ; } int m = mid ; build ( lson ) ; build ( rson ) ; pushup ( o ) ; } void solve () { int u , v , w ; scanf ( n ) ; clear () ; For ( i , 1 , n ) { scanf ( val[i] ) ; } rep ( i , 1 , n ) { scanf ( u ) , scanf ( v ) ; addedge ( u , v ) ; addedge ( v , u ) ; } dfs ( 1 ) ; rewrite ( 1 , 1 ) ; build ( root ) ; scanf ( q ) ; while ( q -- ) { scanf ( u ) , scanf ( v ) , scanf ( w ) ; printf ( "%d\n" , query ( u , v ) ) ; update ( u , v , w ) ; } } int main () { int T ; scanf ( "%d", &T ) ; while ( T -- ) { solve () ; } return 0 ; }