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 MB
Submit: 3239  Solved: 1249
[Submit][Status][Discuss]

Description

给定一棵有n个节点的无根树和m个操作,操作有2类:

1、将节点a到节点b路径上所有点都染成颜色c

2、询问节点a到节点b路径上的颜色段数量(连续相同颜色被认为是同一段),如“1122213段组成:“11、“222和“1

请你写一个程序依次完成这m个操作。

Input

第一行包含2个整数nm,分别表示节点数和操作数;

第二行包含n个正整数表示n个节点的初始颜色

下面 行每行包含两个整数xy,表示xy之间有一条无向边。

下面 行每行描述一个操作:

“C a b c”表示这是一个染色操作,把节点a到节点b路径上所有点(包括ab)都染成颜色c

“Q a b”表示这是一个询问操作,询问节点a到节点b(包括ab)路径上的颜色段数量。

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

Sample Output

3

1

2

HINT

数N<=10^5,操作数M<=10^5,所有的颜色C为整数且在[0, 10^9]之间。

Source

 

posted @ 2015-06-14 00:04  JSZX11556  阅读(211)  评论(0编辑  收藏  举报