BZOJ 3531: [Sdoi2014]旅行( 树链剖分 )

树链剖分..对于每个宗教都建一颗线段树 , 然后动态开点..

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

#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 )
 
using namespace std;
 
const int maxn = 100000 + 5;
const int maxre = int( 1e4 ) + 5;
const int maxedge = maxn << 1;
const int maxnode = int( 1e7 );
 
int n;
 
struct edge { 
int to;
edge* next;
};
 
edge* head[ maxn ] , EDGE[ maxedge ];
edge* pt;
 
inline 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 )
 
void init() {
pt = EDGE;
clr( head , 0 );
}
 
int size[ maxn ] , dep[ maxn ] , fa[ maxn ] , son[ maxn ] , top[ maxn ];
 
void dfs( int x ) {
son[ x ] = -1;
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;
}
}
 
int id_cnt , id[ maxn ] , TOP;
 
void DFS( int x ) {
id[ x ] = ++id_cnt;
top[ x ] = TOP;
if( son[ x ] != -1 ) DFS( son[ x ] );
REP( x ) {
int to = e -> to;
if( to == fa[ x ] || to == son[ x ] ) continue;
DFS( TOP = to );
}
}
 
void dfs_init() {
dfs( dep[ 0 ] = 0 );
DFS( TOP = 0 );
}
 
struct Node {
int ch[ 2 ];
int mx , sum;
Node() {
ch[ 0 ] = ch[ 1 ] = mx = sum = 0;
}
};
 
Node tree[ maxnode ];
int cnt = 1;
#define M( l , r ) ( ( l + r ) >> 1 )
int p , w;
 
void upd( int x ) {
Node &o = tree[ x ] , &L = tree[ o.ch[ 0 ] ] , &R = tree[ o.ch[ 1 ] ];
o.mx = max( L.mx , R.mx );
o.sum = L.sum + R.sum;
}
 
void modify( int &x , int l , int r ) {
if( ! x ) x = cnt++;
Node &o = tree[ x ];
if( p == l && p == r ) {
o.mx = o.sum = w;
} else {
int m = M( l , r );
p <= m ? modify( o.ch[ 0 ] , l , m ) : modify( o.ch[ 1 ] , m + 1 , r );
upd( x );
}
}
 
int L , R;
char op;// S sum , M max
 
int query( int x , int l , int r ) {
if( ! x ) return 0;
Node &o = tree[ x ];
if( L <= l && r <= R )
return op != 'S' ? o.mx : o.sum;
int m = M( l , r );
if( op == 'S' ) return ( L <= m ? query( o.ch[ 0 ] , l , m ) : 0 ) + ( m < R ? query( o.ch[ 1 ] , m + 1 , r ) : 0 );
else return max( L <= m ? query( o.ch[ 0 ] , l , m ) : 0 , m < R ? query( o.ch[ 1 ] , m + 1 , r ) : 0 );
}
 
int h[ maxre ];
int re[ maxn ]; //religion
int le[ maxn ]; //level
  
int Q_M( int x , int y ) {
int res = 0 , T = re[ x ];
while( top[ x ] != top[ y ] ) {
if( dep[ top[ x ] ] < dep[ top[ y ] ] ) swap( x , y );
L = id[ top[ x ] ] , R = id[ x ];
res = max( res , query( h[ T ] , 1 , n ) );
x = fa[ top[ x ] ];
}
if( dep[ x ] > dep[ y ] ) swap( x , y );
L = id[ x ] , R = id[ y ];
return max( res , query( h[ T ] , 1 , n ) );
}
 
int Q_S( int x , int y ) {
int res = 0 , T = re[ x ];
while( top[ x ] != top[ y ] ) {
if( dep[ top[ x ] ] < dep[ top[ y ] ] ) swap( x , y );
L = id[ top[ x ] ] , R = id[ x ];
res += query( h[ T ] , 1 , n );
x = fa[ top[ x ] ];
}
if( dep[ x ] > dep[ y ] ) swap( x , y );
L = id[ x ] , R = id[ y ];
return res + query( h[ T ] , 1 , n );
}
 
int main() {
freopen( "test.in" , "r" , stdin );
init();
int m;
cin >> n >> m;
rep( i , maxre ) h[ i ] = cnt++;
rep( i , n )
scanf( "%d%d" , le + i , re + i );
rep( i , n - 1 ) {
int u , v;
scanf( "%d%d" , &u , &v );
u-- , v--;
add_edge( u , v );
}
dfs_init();
// rep( i , n ) cout << id[ i ] << ' ';
// cout << "\n";
rep( i , n ) {
w = *( le + i );
p = id[ i ];
modify( h[ *( re + i ) ] , 1 , n );
}
char typ;
int x , y;
while( m-- ) {
scanf( " %c%c%d%d" , &typ , &op , &x , &y );
// cout << typ << ' ' << op << "\n";
x--;
if( typ == 'Q' ) 
y-- , printf( "%d\n" , op == 'S' ? Q_S( x , y ) : Q_M( x , y ) );
else 
if( op == 'C' ) {
w = 0;
p = id[ x ];
modify( h[ re[ x ] ] , 1 , n );
re[ x ] = y;
w = le[ x ];
modify( h[ y ] , 1 , n );
} else {
le[ x ] = w = y;
p = id[ x ];
modify( h[ re[ x ] ] , 1 , n );
}
}
   
return 0;
}

  

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

3531: [Sdoi2014]旅行

Time Limit: 20 Sec  Memory Limit: 512 MB
Submit: 669  Solved: 346
[Submit][Status][Discuss]

Description

 S国有N个城市,编号从1到N。城市间用N-1条双向道路连接,满足
从一个城市出发可以到达其它所有城市。每个城市信仰不同的宗教,如飞天面条神教、隐形独角兽教、绝地教都是常见的信仰。为了方便,我们用不同的正整数代表各种宗教,  S国的居民常常旅行。旅行时他们总会走最短路,并且为了避免麻烦,只在信仰和他们相同的城市留宿。当然旅程的终点也是信仰与他相同的城市。S国政府为每个城市标定了不同的旅行评级,旅行者们常会记下途中(包括起点和终点)留宿过的城市的评级总和或最大值。
    在S国的历史上常会发生以下几种事件:
”CC x c”:城市x的居民全体改信了c教;
”CW x w”:城市x的评级调整为w;
”QS x y”:一位旅行者从城市x出发,到城市y,并记下了途中留宿过的城市的评级总和;
”QM x y”:一位旅行者从城市x出发,到城市y,并记下了途中留宿过
的城市的评级最大值。
    由于年代久远,旅行者记下的数字已经遗失了,但记录开始之前每座城市的信仰与评级,还有事件记录本身是完好的。请根据这些信息,还原旅行者记下的数字。    为了方便,我们认为事件之间的间隔足够长,以致在任意一次旅行中,所有城市的评级和信仰保持不变。

Input

    输入的第一行包含整数N,Q依次表示城市数和事件数。
    接下来N行,第i+l行两个整数Wi,Ci依次表示记录开始之前,城市i的
评级和信仰。
    接下来N-1行每行两个整数x,y表示一条双向道路。
    接下来Q行,每行一个操作,格式如上所述。

Output

    对每个QS和QM事件,输出一行,表示旅行者记下的数字。

Sample Input

5 6
3 1
2 3
1 2
3 3
5 1
1 2
1 3
3 4
3 5
QS 1 5
CC 3 1
QS 1 5
CW 3 3
QS 1 5
QM 2 4

Sample Output

8
9
11
3

HINT

N,Q < =10^5    , C < =10^5


 数据保证对所有QS和QM事件,起点和终点城市的信仰相同;在任意时

刻,城市的评级总是不大于10^4的正整数,且宗教值不大于C。

Source

 

posted @ 2015-06-22 21:54  JSZX11556  阅读(197)  评论(0编辑  收藏  举报