BZOJ 2243: [SDOI2011]染色( 树链剖分 )
树链剖分...细节挺多的...
---------------------------------------------------------------------------------
#include<cstdio>
#include<cstring>
#include<algorithm>
#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 REP( x ) for( edge* e = head[ x ] ; e ;e = e -> next )
#define M( l , r ) ( ( l + r ) >> 1 )
#define L( x ) ( ( x ) << 1 )
#define R( x ) ( L( x ) ^ 1 )
#define LC L( x ) , l , m
#define RC R( x ) , m + 1 , r
#define X x , l , r
#define XX int x , int l , int r
#define All 1 , 1 , n
using namespace std;
const int maxn = 100000 + 5;
const int maxnode = 270000;
int n;
int seq[ maxn ];
struct edge {
int to;
edge* next;
};
edge* pt , EDGE[ maxn << 1 ];
edge* head[ maxn ];
void edge_init() {
pt = EDGE;
clr( head , 0 );
}
void add( int u , int v ) {
pt -> to = v;
pt -> next = head[ u ];
head[ u ] = pt++;
}
#define add_edge( u , v ) add( u , v ) , add( v , u )
int top[ maxn ] , fa[ maxn ] , dep[ maxn ] , size[ maxn ] , son[ maxn ];
int id[ maxn ] , _id[ maxn ] , id_cnt = 0 , TOP;
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 );
size[ x ] += size[ to ];
if( son[ x ] == -1 || size[ to ] > size[ son[ x ] ] )
son[ x ] = to;
}
}
void DFS( int x ) {
id[ x ] = ++id_cnt;
_id[ id_cnt ] = x;
top[ x ] = TOP;
if( son[ x ] != -1 )
DFS( son[ x ] );
REP( x ) if( id[ e -> to ] < 0 )
DFS( TOP = e -> to );
}
void DFS_init() {
clr( id , -1 );
clr( son , -1 );
dfs( dep[ 0 ] = 0 );
DFS( TOP = 0 );
}
int l_c[ maxnode ] , r_c[ maxnode ] , sum[ maxnode ] , set[ maxnode ];
int L , R , v , query_ans , find_id;
void maintain( XX ) {
if( set[ x ] >= 0 || l == r ) {
l_c[ x ] = r_c[ x ] = set[ x ];
sum[ x ] = 1;
} else {
sum[ x ] = sum[ L( x ) ] + sum[ R( x ) ] - ( r_c[ L( x ) ] == l_c[ R( x ) ] );
l_c[ x ] = l_c[ L( x ) ];
r_c[ x ] = r_c[ R( x ) ];
}
}
void pushdown( XX ) {
if( set[ x ] >= 0 ) {
set[ L( x ) ] = set[ R( x ) ] = set[ x ];
l_c[ L( x ) ] = l_c[ R( x ) ] = l_c[ x ];
r_c[ L( x ) ] = r_c[ R( x ) ] = r_c[ x ];
set[ x ] = -1;
}
}
void update( XX ) {
if( L <= l && r <= R ) {
set[ x ] = l_c[ x ] = r_c[ x ] = v;
sum[ x ] = 1;
} else {
int m = M( l , r );
pushdown( X );
maintain( LC );
maintain( RC );
if( L <= m ) update( LC );
if( m < R ) update( RC );
maintain( X );
}
}
void Update( int l , int r ) {
L= l , R = r;
update( All );
}
void query( XX ) {
if( L <= l && r <= R ) {
query_ans += sum[ x ];
} else {
int m = M( l , r ) , t[ 2 ] = { -1 , -1 };
pushdown( X );
maintain( LC );
maintain( RC );
if( L <= m )
query( LC ) , t[ 0 ] = r_c[ L( x ) ];
if( m < R )
query( RC ) , t[ 1 ] = l_c[ R( x ) ];
if( t[ 0 ] == t[ 1 ] && t[ 0 ] != -1 )
query_ans--;
}
}
int Query( int l , int r ) {
L = l , R = r;
query_ans = 0;
query( All );
return query_ans;
}
int find( XX ) {
if( l == r )
return set[ x ];
int m = M( l , r );
pushdown( X );
maintain( LC );
maintain( RC );
return find_id <= m ? find( LC ) : find( RC );
}
int Find( int v ) {
find_id = v;
return find( All );
}
void build( XX ) {
if( l == r ) {
sum[ x ] = 1;
set[ x ] = l_c[ x ] = r_c[ x ] = seq[ _id[ l ] ];
} else {
set[ x ] = -1;
int m = M( l , r );
build( LC );
build( RC );
maintain( X );
}
}
void modify( int x , int y ) {
while( top[ x ] != top[ y ] ) {
if( dep[ top[ x ] ] < dep[ top[ y ] ] )
swap( x , y );
Update( id[ top[ x ] ] , id[ x ] );
x = fa[ top[ x ] ];
}
if( dep[ x ] > dep[ y ] )
swap( x , y );
Update( id[ x ] , id[ y ] );
}
int Q( int x , int y ) {
int res = 0;
while( top[ x ] != top[ y ] ) {
if( dep[ top[ x ] ] < dep[ top[ y ] ] )
swap( x , y );
res += Query( id[ top[ x ] ] , id[ x ] );
int t[ 2 ] = { Find( id[ fa[ top[ x ] ] ] ) , Find( id[ top[ x ] ] ) };
if( t[ 0 ] == t[ 1 ] ) res--;
x = fa[ top[ x ] ];
}
if( dep[ x ] > dep[ y ] )
swap( x , y );
return res + Query( id[ x ] , id[ y ] );
}
int main() {
freopen( "test.in" , "r" , stdin );
freopen( "test.out" , "w" , stdout );
int m;
cin >> n >> m;
rep( i , n )
scanf( "%d" , seq + i );
edge_init();
rep( i , n - 1 ) {
int u , v;
scanf( "%d%d" , &u , &v );
u-- , v--;
add_edge( u , v );
}
DFS_init();
build( 1 , 1 , n );
while( m-- ) {
char type;
int x , y;
scanf( " %c%d%d" , &type , &x , &y );
x-- , y--;
if( type == 'C' ) {
scanf( "%d" , &v );
modify( x , y );
} else
printf( "%d\n" , Q( x , y ) );
}
return 0;
}
---------------------------------------------------------------------------------
2243: [SDOI2011]染色
Time Limit: 20 Sec Memory Limit: 512 MBSubmit: 3239 Solved: 1249
[Submit][Status][Discuss]
Description
给定一棵有n个节点的无根树和m个操作,操作有2类:
1、将节点a到节点b路径上所有点都染成颜色c;
2、询问节点a到节点b路径上的颜色段数量(连续相同颜色被认为是同一段),如“112221”由3段组成:“11”、“222”和“1”。
请你写一个程序依次完成这m个操作。
Input
第一行包含2个整数n和m,分别表示节点数和操作数;
第二行包含n个正整数表示n个节点的初始颜色
下面 行每行包含两个整数x和y,表示x和y之间有一条无向边。
下面 行每行描述一个操作:
“C a b c”表示这是一个染色操作,把节点a到节点b路径上所有点(包括a和b)都染成颜色c;
“Q a b”表示这是一个询问操作,询问节点a到节点b(包括a和b)路径上的颜色段数量。
Output
对于每个询问操作,输出一行答案。
Sample Input
6 5
2 2 1 2 1 1
1 2
1 3
2 4
2 5
2 6
Q 3 5
C 2 1 1
Q 3 5
C 5 1 2
Q 3 5
2 2 1 2 1 1
1 2
1 3
2 4
2 5
2 6
Q 3 5
C 2 1 1
Q 3 5
C 5 1 2
Q 3 5
Sample Output
3
1
2
1
2
HINT
数N<=10^5,操作数M<=10^5,所有的颜色C为整数且在[0, 10^9]之间。
Source