BZOJ 1036: [ZJOI2008]树的统计Count( 树链剖分 )
树链剖分...
不知道为什么跑这么慢 = = 调了一节课啊跪..
-------------------------------------------------------------------------------
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<iostream>
#define rep( i , n ) for( int i = 0 ; i < n ; ++i )
#define clr( x , c ) memset( x , c , sizeof( x ) )
#define Rep( i , n ) for( int i = 1 ; i <= n ; ++i )
#define L( x ) ( x << 1 )
#define R( x ) ( L( x ) ^ 1 )
#define mid( l , r ) ( ( l + r ) >> 1 )
#define LC( x ) tree[ L( x ) ]
#define RC( x ) tree[ R( x ) ]
#define REP( x ) for( edge* e = head[ x ] ; e ; e = e -> next )
using namespace std;
const int maxn = 30000 + 5;
const int inf = 0x7fffffff;
int fa[ maxn ] , w[ maxn ] , size[ maxn ] , dep[ maxn ] , top[ maxn ] , son[ maxn ];
int id_cnt = 0 , id[ maxn ] , id_r[ maxn ];
int n;
struct edge {
int to;
edge* next;
};
edge* pt , EDGE[ maxn << 1 ];
edge* head[ maxn ];
void add( int u , int v ) {
pt -> to = v;
pt -> next = head[ u ];
head[ u ] = pt++;
}
void init() {
pt = EDGE;
clr( head , 0 );
}
#define add_edge( u , v ) add( u , v ) , add( v , u )
void dfs( int x ) {
size[ x ] = 1;
REP( x ) {
int to = e -> to;
if( to == fa[ x ] ) continue;
dep[ to ] = dep[ x ] + 1;
fa[ to ] = x;
dfs( to );
if( son[ x ] == -1 || size[ to ] > size[ son[ x ] ] )
son[ x ] = to;
size[ x ] += size[ to ];
}
}
int TOP;
void Dfs( int x ) {
id[ x ] = ++id_cnt;
id_r[ id[ x ] ] = x;
top[ x ] = TOP;
if( son[ x ] != -1 )
Dfs( son[ x ] );
REP( x ) if( id[ e -> to ] < 0 )
Dfs( TOP = e -> to );
}
void _init() {
clr( id , -1 );
clr( son , -1 );
dfs( dep[ 0 ] = 0 );
Dfs( TOP = 0 );
}
struct Node {
int l , r , Max , sum;
};
Node tree[ maxn << 4 ];
int L , R , op;//1MAX 0 SUM
int u , v;
void maintain( int x ) {
Node &o = tree[ x ];
if( o. r > o.l ) {
o.sum = LC( x ).sum + RC( x ).sum;
o.Max = max( LC( x ).Max , RC( x ).Max );
}
}
void update( int x ) {
Node &o = tree[ x ];
if( o.l == L && o.r == L )
o.sum = o.Max = R;
else {
int m = mid( o.l , o.r );
update( L <= m ? L( x ) : R( x ) );
maintain( x );
}
}
int query( int x ) {
Node &o = tree[ x ];
if( L <= o.l && o.r <= R )
return op ? o.Max : o.sum;
int m = mid( o.l , o.r );
int ans;
if( ! op ) {
ans = 0;
if( L <= m ) ans += query( L( x ) );
if( m < R ) ans += query( R( x ) );
} else {
ans = -inf;
if( L <= m ) ans = max( ans , query( L( x ) ) );
if( m < R ) ans = max( ans , query( R( x ) ) );
}
return ans;
}
void build( int x , int l , int r ) {
Node &o = tree[ x ];
o.l = l , o.r = r;
if( l == r )
o.Max = o.sum = w[ id_r[ l ] ];
else {
int m = mid( l , r );
build( L( x ) , l , m );
build( R( x ) , m + 1 , r );
maintain( x );
}
}
int Qsum() {
int ans = op = 0;
while( top[ u ] != top[ v ] ) {
if( dep[ top[ u ] ] < dep[ top[ v ] ] )
swap( u , v );
L = id[ top[ u ] ] , R = id[ u ];
ans += query( 1 );
u = fa[ top[ u ] ];
}
if( dep[ u ] > dep[ v ] ) swap( u , v );
L = id[ u ] , R = id[ v ];
return ans + query( 1 );
}
int Qmax() {
int ans = -inf;
op = 1;
while( top[ u ] != top[ v ] ) {
if( dep[ top[ u ] ] < dep[ top[ v ] ] )
swap( u , v );
L = id[ top[ u ] ] , R = id[ u ];
ans = max( ans , query( 1 ) );
u = fa[ top[ u ] ];
}
if( dep[ u ] > dep[ v ] ) swap( u , v );
L = id[ u ] , R = id[ v ];
return max( ans , query( 1 ) );
}
int main() {
freopen( "test.in" , "r" , stdin );
freopen( "test.out" ,"w" , stdout);
init();
cin >> n;
rep( i , n - 1 ) {
int u , v;
scanf( "%d%d" , &u , &v );
u-- , v--;
add_edge( u , v );
}
rep( i , n ) scanf( "%d" , w + i );
_init();
build( 1 , 1 , n );
int m;
cin >> m;
while( m-- ) {
char s[ 10 ];
scanf( " %s" , s );
scanf( "%d%d" , &u , &v );
u-- , v--;
if( s[ 0 ] == 'C' ) {
L = id[ u ];
R = v + 1;
update( 1 );
} else {
if( s[ 1 ] == 'S' ) printf( "%d\n" , Qsum() );
else printf( "%d\n" , Qmax() );
}
}
return 0;
}
-------------------------------------------------------------------------------
1036: [ZJOI2008]树的统计Count
Time Limit: 10 Sec Memory Limit: 162 MBSubmit: 7694 Solved: 3155
[Submit][Status][Discuss]
Description
一棵树上有n个节点,编号分别为1到n,每个节点都有一个权值w。我们将以下面的形式来要求你对这棵树完成一些操作: I. CHANGE u t : 把结点u的权值改为t II. QMAX u v: 询问从点u到点v的路径上的节点的最大权值 III. QSUM u v: 询问从点u到点v的路径上的节点的权值和 注意:从点u到点v的路径上的节点包括u和v本身
Input
输入的第一行为一个整数n,表示节点的个数。接下来n – 1行,每行2个整数a和b,表示节点a和节点b之间有一条边相连。接下来n行,每行一个整数,第i行的整数wi表示节点i的权值。接下来1行,为一个整数q,表示操作的总数。接下来q行,每行一个操作,以“CHANGE u t”或者“QMAX u v”或者“QSUM u v”的形式给出。 对于100%的数据,保证1<=n<=30000,0<=q<=200000;中途操作中保证每个节点的权值w在-30000到30000之间。
Output
对于每个“QMAX”或者“QSUM”的操作,每行输出一个整数表示要求输出的结果。
Sample Input
4
1 2
2 3
4 1
4 2 1 3
12
QMAX 3 4
QMAX 3 3
QMAX 3 2
QMAX 2 3
QSUM 3 4
QSUM 2 1
CHANGE 1 5
QMAX 3 4
CHANGE 3 6
QMAX 3 4
QMAX 2 4
QSUM 3 4
1 2
2 3
4 1
4 2 1 3
12
QMAX 3 4
QMAX 3 3
QMAX 3 2
QMAX 2 3
QSUM 3 4
QSUM 2 1
CHANGE 1 5
QMAX 3 4
CHANGE 3 6
QMAX 3 4
QMAX 2 4
QSUM 3 4
Sample Output
4
1
2
2
10
6
5
6
5
16
1
2
2
10
6
5
6
5
16
HINT
Source