您的位置:首页 > 其它

BZOJ 1036: [ZJOI2008]树的统计Count( 树链剖分 )

2015-06-11 21:48 495 查看


树链剖分...

不知道为什么跑这么慢 = = 调了一节课啊跪..

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

#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 SUMint 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 MB
Submit: 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

Sample Output

4
1
2
2
10
6
5
6
5
16

HINT

Source

树的分治
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: