BZOJ 1984: 月下“毛景树”( 树链剖分 )

水水的树链剖分... 将边上的权值转到深度较大的点上 , 然后要注意这样做之后修改或者查询 u , v 转到同一条重链上时 ( 假设 u 深度小 ) , 不能把 u 的权值算上 , 因为是 u 和它的 fa 的边的权值 , 从 u 到 v 并没有经过这条边

线段树维护 3 个域 set , add , max . 

----------------------------------------------------------------------------

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cstdlib>
#include<iostream>
 
#define rep( i , n ) for( int i = 0 ; i < n ; ++i )
#define clr( x , c ) memset( x , c , sizeof( x ) )
#define REP( x ) for( edge* e = head[ x ] ; e ; e = e -> next )
#define Rep( i , n ) for( int i = 1 ; i <= n ; ++i )
#define M( l , r ) ( ( ( l ) + ( r ) ) >> 1 )
 
using namespace std;
 
const int maxn = 200000 + 5;
const int inf = 1e9 + 10;
 
struct edge {
int to , w;
edge* next;
}  E[ maxn << 1 ] , *pit = E , *head[ maxn ];
 
inline void add_edge( int u , int v , int d ) {
pit -> to = v;
pit -> w = d;
pit -> next = head[ u ];
head[ u ] = pit++;
pit -> to = u;
pit -> w = d;
pit -> next = head[ v ];
head[ v ] = pit++;
}
 
int top[ maxn ] , fa[ maxn ] , dep[ maxn ] , son[ maxn ] , size[ maxn ];
int val[ maxn ] , id[ maxn ] , id_cnt = 0 , TOP , n;
 
void dfs( int x ) {
son[ x ] = -1 , size[ x ] = 1;
REP( x ) if( e -> to != fa[ x ] ) {
fa[ e -> to ] = x;
dep[ e -> to ] = dep[ x ] + 1;
dfs( e -> to );
size[ x ] += size[ e -> to ];
if( son[ x ] == -1 || size[ son[ x ] ] < size[ e -> to ] )
   son[ x ] = e -> to;
}
}
 
void DFS( int x ) {
top[ x ] = TOP;
id[ x ] = ++id_cnt;
if( son[ x ] != -1 ) DFS( son[ x ] );
REP( x ) if( e -> to != fa[ x ] && son[ x ] != e -> to )
   DFS( TOP = e -> to );
}
 
void Dfs( int x ) {
REP( x ) if( e -> to != fa[ x ] ) {
   val[ id[ e -> to ] ] = e -> w;
   Dfs( e -> to );
}
}
 
void init() {
val[ 1 ] = 0;
fa[ 0 ] = -1;
dfs( dep[ 0 ] = 0 );
DFS( TOP = 0 );
Dfs( 0 );
}
 
struct Node {
Node *l , *r;
int mx , add , set;
Node() : add( 0 ) , set( -1 ) {
l = r = NULL;
}
inline void update() {
if( set != -1 )
mx = set;
else if( l )
mx = max( l -> mx , r -> mx );
mx += add;
}
inline void pushdown() {
if( set != -1 ) {
l -> set = r -> set = set;
l -> add = r -> add = 0;
set = -1;
}
if( add ) {
l -> add += add;
r -> add += add;
add = 0;
}
}
} pool[ maxn << 1 ] , *pt = pool , *root;
 
int L , R , v;
bool type; // type = false : cover , type = true : add
 
void build( Node* t , int l , int r ) {
if( r > l ) {
int m = M( l , r );
build( t -> l = pt++ , l , m );
build( t -> r = pt++ , m + 1 , r );
} else
   t -> set = val[ l ];
t -> update();
}
 
void modify( Node* t , int l , int r ) {
if( L <= l && r <= R )
type ? t -> add += v : ( t -> add = 0 , t -> set = v );
else {
t -> pushdown();
int m = M( l , r );
L <= m ? modify( t -> l , l , m ) : t -> l -> update();
m < R ? modify( t -> r , m + 1 , r ) : t -> r -> update();
}
t -> update();
}
 
void change( Node* t , int l , int r ) {
if( l == r ) 
   t -> set = v , t -> add = 0;
else {
t -> pushdown();
int m = M( l , r );
if( L <= m ) 
   change( t -> l , l , m ) , t -> r -> update();
else
   change( t -> r , m + 1 , r ) , t -> l -> update();
}
t -> update();
}
 
int query( Node* t , int l , int r ) {
if( L <= l && r <= R ) 
   return t -> mx;
t -> pushdown();
t -> l -> update();
t -> r -> update();
int m = M( l , r );
return max( ( L <= m ? query( t -> l , l , m ) : -inf ) , 
           ( m < R ? query( t -> r , m + 1 , r ) : -inf ) );
}
  
int Max( int u , int v ) {
int ans = -inf;
for( ; top[ u ] != top[ v ] ; u = fa[ top[ u ] ] ) {
if( dep[ top[ u ] ] < dep[ top[ v ] ] ) swap( u , v );
L = id[ top[ u ] ] , R = id[ u ];
ans = max( ans , query( root , 1 , n ) );
}
if( u == v ) return ans;
if( dep[ u ] < dep[ v ] ) swap( u , v );
L = id[ v ] + 1 , R = id[ u ];
return max( ans , query( root , 1 , n ) );
}
 
void Cover( int u , int v ) {
type = false;
for( ; top[ u ] != top[ v ] ; u = fa[ top[ u ] ] ) {
if( dep[ top [ u ] ] < dep[ top[ v ] ] ) swap( u , v );
L = id[ top[ u ] ] , R = id[ u ];
modify( root , 1 , n );
}
if( u == v ) return;
if( dep[ u ] < dep[ v ] ) swap( u , v );
L = id[ v ] + 1 , R = id[ u ];
modify( root , 1 , n );
}
 
void Add( int u , int v ) {
type = true;
for( ; top[ u ] != top[ v ] ; u = fa[ top[ u ] ] ) {
if( dep[ top[ u ] ] < dep[ top[ v ] ] ) swap( u , v );
L = id[ top[ u ] ] , R = id[ u ];
modify( root , 1 , n );
}
if( u == v ) return;
if( dep[ u ] < dep[ v ] ) swap( u , v );
L = id[ v ] + 1 , R = id[ u ];
modify( root , 1 , n );
}
 
int branch[ maxn ][ 2 ];
 
int main() {
freopen( "test.in" , "r" , stdin );
clr( head , 0 );
cin >> n;
rep( i , n - 1 ) {
int d;
scanf( "%d%d%d" , &branch[ i ][ 0 ] , &branch[ i ][ 1 ] , &d );
add_edge( --branch[ i ][ 0 ] , --branch[ i ][ 1 ]  , d );
}
init();
build( root = pt++ , 1 , n );
char s[ 10 ];
int x , y;
for( ; ; ) {
scanf( " %s" , s );
if( s[ 0 ] == 'S' ) break;
scanf( "%d%d" , &x , &y );
x-- , y--;
if( s[ 0 ] == 'M' )
printf( "%d\n" , Max( x , y ) );
else if( s[ 1 ] == 'h' ) {
if( dep[ branch[ x ][ 0 ] ] > dep[ branch[ x ][ 1 ] ] )
   L = id[ branch[ x ][ 0 ] ];
else
   L = id[ branch[ x ][ 1 ] ];
   v = y + 1;
change( root , 1 , n );
} else
scanf( "%d" , &v ) ,
s[ 0 ] == 'C' ? Cover( x , y ) : Add( x , y );
}
return 0;
}

 

---------------------------------------------------------------------------- 

 

1984: 月下“毛景树”

Time Limit: 20 Sec  Memory Limit: 64 MB
Submit: 1036  Solved: 338
[Submit][Status][Discuss]

Description

毛毛虫经过及时的变形,最终逃过的一劫,离开了菜妈的菜园。 毛毛虫经过千山万水,历尽千辛万苦,最后来到了小小的绍兴一中的校园里。爬啊爬~爬啊爬~~毛毛虫爬到了一颗小小的“毛景树”下面,发现树上长着他最爱吃的毛毛果~~~ “毛景树”上有N个节点和N-1条树枝,但节点上是没有毛毛果的,毛毛果都是长在树枝上的。但是这棵“毛景树”有着神奇的魔力,他能改变树枝上毛毛果的个数:  Change k w:将第k条树枝上毛毛果的个数改变为w个。  Cover u v w:将节点u与节点v之间的树枝上毛毛果的个数都改变为w个。  Add u v w:将节点u与节点v之间的树枝上毛毛果的个数都增加w个。 由于毛毛虫很贪,于是他会有如下询问:  Max u v:询问节点u与节点v之间树枝上毛毛果个数最多有多少个。

Input

第一行一个正整数N。 接下来N-1行,每行三个正整数Ui,Vi和Wi,第i+1行描述第i条树枝。表示第i条树枝连接节点Ui和节点Vi,树枝上有Wi个毛毛果。 接下来是操作和询问,以“Stop”结束。

Output

对于毛毛虫的每个询问操作,输出一个答案。

Sample Input

4
1 2 8
1 3 7
3 4 9
Max 2 4
Cover 2 4 5
Add 1 4 10
Change 1 16
Max 2 4
Stop

Sample Output

9
16

【Data Range】
1<=N<=100,000,操作+询问数目不超过100,000。
保证在任意时刻,所有树枝上毛毛果的个数都不会超过10^9个。

HINT

Source

 

posted @ 2015-07-12 17:49  JSZX11556  阅读(324)  评论(1编辑  收藏  举报