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

树的分治

时间: 2024-10-04 12:51:58

BZOJ 1984: 月下“毛景树”( 树链剖分 )的相关文章

【BZOJ】1984 月下“毛景树”

[算法]树链剖分+线段树 [题解]线段树的区间加值和区间覆盖操作不能同时存在,只能存在一个. 修改:从根节点跑到目标区域路上的标记全部下传,打完标记再上传回根节点(有变动才需要上传). 询问:访问到目标区域路上的标记全部下传. 我写的线段树版本是在打标记的同时便对该点的询问项(最大值)做了对应更改,即可保证访问到该点得到的ms就是该点的答案. 访问某点时如果要询问最大值就直接拿走,如果要还要访问该点的子节点就需要下传. 而修改了某点的值,它的祖先的值就都需要变动,所以一旦修改必须上传至顶. 对于

[BZOJ1984] 月下“毛景树”|树链剖分|线段树

1984: 月下“毛景树” Time Limit: 20 Sec  Memory Limit: 64 MBSubmit: 1088  Solved: 348[Submit][Status][Discuss] Description 毛毛虫经过及时的变形,最终逃过的一劫,离开了菜妈的菜园. 毛毛虫经过千山万水,历尽千辛万苦,最后来到了小小的绍兴一中的校园里.爬啊爬~爬啊爬~~毛毛虫爬到了一颗小小的“毛景树”下面,发现树上长着他最爱吃的毛毛果~~~ “毛景树”上有N个节点和N-1条树枝,但节点上是没

【BZOJ1984】月下“毛景树” 树链剖分+线段树

[BZOJ1984]月下"毛景树" Description 毛毛虫经过及时的变形,最终逃过的一劫,离开了菜妈的菜园. 毛毛虫经过千山万水,历尽千辛万苦,最后来到了小小的绍兴一中的校园里.爬啊爬~爬啊爬~~毛毛虫爬到了一颗小小的"毛景树"下面,发现树上长着他最爱吃的毛毛果~~~ "毛景树"上有N个节点和N-1条树枝,但节点上是没有毛毛果的,毛毛果都是长在树枝上的.但是这棵"毛景树"有着神奇的魔力,他能改变树枝上毛毛果的个数: ?

P4315 月下“毛景树”

P4315 月下"毛景树" 题目描述 毛毛虫经过及时的变形,最终逃过的一劫,离开了菜妈的菜园. 毛毛虫经过千山万水,历尽千辛万苦,最后来到了小小的绍兴一中的校园里. 爬啊爬~爬啊爬毛毛虫爬到了一颗小小的"毛景树"下面,发现树上长着他最爱吃的毛毛果~ "毛景树"上有N个节点和N-1条树枝,但节点上是没有毛毛果的,毛毛果都是长在树枝上的.但是这棵"毛景树"有着神奇的魔力,他能改变树枝上毛毛果的个数: Change k w:将第k条

[luogu4315]月下“毛景树”

[luogu4315]月下"毛景树" luogu 联赛前复习一发树剖.不会告诉你WA了4发 #define ls x<<1,l,mid #define rs x<<1|1,mid+1,r #include<bits/stdc++.h> using namespace std; const int _=1e5+5; int re(){ int x=0,w=1;char ch=getchar(); while(ch<'0'||ch>'9'){

[BZOJ1984]月下“毛景树”解题报告|树链剖分

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

bzoj1984 月下“毛景树”

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

题解 P4315 【月下“毛景树”】

题目链接:Luogu P4315 线段树 \(+\) 树链剖分 \[\Large\texttt{description}\] 给定一棵\(n\)个节点的树,有\(n - 1\)条边相连,给出\(u_i~v_i~w_i\) 分别表示 \(u_i,v_i\)有一条边,边权是\(w_i\) 有\(3\)种操作以及\(1\)种询问 \(\bullet\) Change k w:将第k条树枝上毛毛果的个数改变为w个 \(\bullet\) Cover u v w:将节点u与节点v之间的树枝上毛毛果的个数都

【树链剖分】【分块】【最近公共祖先】【块状树】bzoj1984 月下“毛景树”

裸题,但是因为权在边上,所以要先把边权放到这条边的子节点上,然后进行链更新/查询的时候不能更新/查询其lca. #include<cstdio> #include<cmath> #include<algorithm> using namespace std; #define N 100001 #define BN 320 #define INF 2147483647 int fa[N],dep[N],siz[N],son[N],Num[N],tot,top[N],a[N