说在前面
Emmmmm….和预想差不多,两个半小时AC此题=w=
很久没有写过带修改莫队了,正好也练习一下树上莫队,然后就去码了这题…me的代码真是长到了一种境界
这道题的数据还是很不错的,让me找出了板子里一些细节错误
题目
题目大意
给出一棵有N个节点的树,节点有各自的权值,权值均为非负整数。现在需要维护以下操作:
1. 0 u x :将u节点的点权修改为x
2. 1 u v :询问u到v路径上,没有出现过的最小非负整数
数据范围:N和M均不超过50000
时限:40 seconds
输入输出格式
输入格式:
第一行两个整数N,M,表示节点数和操作数
接下来N-1行,每行两个数u v,描述一条树边
再接下来M行,每行三个数,描述一个操作,格式如题
输出格式:
对于每个询问操作,输出权值
解法
OS:看到 这么小 的数据范围,这么 宽松 的时间….肯定是用莫队直接秒掉嘛 QwQ
具体做法:
关于「树上分块」,参见 BZOJ1089 王室联邦
关于「树上莫队」,参见 SPOJ COT2
关于「带修改莫队」,参见 BZOJ2120 数颜色
关于「用莫队+分块求最小未出现数」,参见 BZOJ3585 mex
下面是自带大长度的代码
/**************************************************************
Problem: 4129
User: Izumihanako
Language: C++
Result: Accepted
Time:924 ms
Memory:10780 kb
****************************************************************/
#include <cmath>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std ;
int N , M , tp , head[50005] ;
int val[50005] , mcnt , qcnt ;
int Bsiz , Btot , bel[50005] ;
int fa[16][50005] , dep[50005] , ans[50005] ;
struct Modifies{
int pos , val , pre , tim ;
}m[50005] ;
struct Queries{
int u , v , tim ;
bool operator < ( const Queries &A ) const {
return bel[u] < bel[A.u] ||
( bel[u] == bel[A.u] && bel[v] < bel[A.v] ) ||
( bel[u] == bel[A.u] && bel[v] == bel[A.v] && tim < A.tim ) ;
}
}q[50005] ;
struct num_Block{
int Bsiz_ , Btot_ , cnt_[50005] ;
int bel_[50005] , st_[350] , ed_[350] , fullsiz_[350] , Bcnt_[350] ;
void init(){
Bsiz_ = sqrt( N ) ;
Btot_ = ( N / Bsiz_ ) + ( bool )( N %Bsiz_ ) ;
for( int i = 1 ; i <= Btot_ ; i ++ ){
st_[i] = ed_[i-1] + 1 ;
ed_[i] = min( st_[i] + Bsiz_ - 1 , N ) ;
fullsiz_[i] = ed_[i] - st_[i] + 1 ;
for( int j = st_[i] ; j <= ed_[i] ; j ++ )
bel_[j] = i ;
}
st_[Btot_+1] = N + 1 ;
ed_[Btot_+1] = 0x3f3f3f3f ;
fullsiz_[Btot_+1] = 0x3f3f3f3f - N ;
}
void Insert( int x ){
if( x > N ) return ;
cnt_[x] ++ ;
if( cnt_[x] == 1 ) Bcnt_[ bel_[x] ] ++ ;
}
void Erase( int x ){
if( x > N ) return ;
cnt_[x] -- ;
if( cnt_[x] == 0 ) Bcnt_[ bel_[x] ] -- ;
}
int Query(){
int tmp ;
for( int i = 1 ; i <= Btot_ + 1 ; i ++ )
if( Bcnt_[i] != fullsiz_[i] ){ tmp = i ; break ; }
for( int i = st_[tmp] ; i <= ed_[tmp] ; i ++ )
if( !cnt_[i] ) return i ;
}
}B ;
struct Path{
int pre , to ;
}p[100005] ;
void In( int t1 , int t2 ){
p[++tp].pre = head[t1] ;
p[ head[t1] = tp ].to = t2 ;
}
int sta[50005] , topp ;
void dfs( int u ){
int las = topp ;
for( int i = head[u] ; i ; i = p[i].pre ){
int v = p[i].to ;
if( v == fa[0][u] ) continue ;
fa[0][v] = u ;
dep[v] = dep[u] + 1 ;
dfs( v ) ;
if( topp - las >= Bsiz ){
Btot ++ ;
while( topp != las ) bel[ sta[topp--] ] = Btot ;
}
}
sta[++topp] = u ;
}
void get_ST(){
for( int i = 1 ; i <= 15 ; i ++ )
for( int j = 1 ; j <= N ; j ++ )
fa[i][j] = fa[i-1][ fa[i-1][j] ] ;
}
int Lca( int u , int v ){
if( dep[u] < dep[v] ) swap( u , v ) ;
int t = dep[u] - dep[v] , x = 0 ;
while( t ){
if( t&1 ) u = fa[x][u] ;
t >>= 1 , x ++ ;
}
if( u == v ) return u ;
for( int i = 15 ; i >= 0 ; i -- )
if( fa[i][u] != fa[i][v] )
u = fa[i][u] , v = fa[i][v] ;
return fa[0][u] ;
}
void init(){
Bsiz = (int) pow( N , 2.0 / 3.0 ) ;
dfs( 1 ) ; fa[0][1] = 1 ;
get_ST() ;
if( topp ){
Btot ++ ;
while( topp ) bel[ sta[topp--] ] = Btot ;
}
B.init() ;
sort( q + 1 , q + qcnt + 1 ) ;
}
bool vis[50005] ;
void Change( int u , int x ){
if( vis[u] ) B.Erase( val[u] ) ;
val[u] = x ;
if( vis[u] ) B.Insert( val[u] ) ;
}
void Xor( int u ){
vis[u] ^= 1 ;
if( !vis[u] ) B.Erase( val[u] ) ;
else B.Insert( val[u] ) ;
}
void Move( int u , int v ){
if( dep[u] < dep[v] ) swap( u , v ) ;
while( dep[u] > dep[v] ){
Xor( u ) ;
u = fa[0][u] ;
}
while( u != v ){
Xor( u ) ; Xor( v ) ;
u = fa[0][u] , v = fa[0][v] ;
}
}
void solve(){
int nowU = 1 , nowV = 1 , T = 1 ;
for( int i = 1 ; i <= qcnt ; i ++ ){
int u = q[i].u , v = q[i].v , tim = q[i].tim , LCA = Lca( u , v ) ;
while( m[T].tim < tim ){
Change( m[T].pos , m[T].val ) ;
T ++ ;
}
while( m[T-1].tim > tim ){
Change( m[T-1].pos , m[T-1].pre ) ;
T -- ;
}
Move( nowU , u ) ; nowU = u ;
Move( nowV , v ) ; nowV = v ;
Xor( LCA ) ;
ans[tim] = B.Query() ;
Xor( LCA ) ;
}
for( int i = 1 ; i <= M ; i ++ )
if( ans[i] ) printf( "%d\n" , ans[i] - 1 ) ;
}
inline void read_( int &x ){
x = 0 ;//传引用, 需要清空值
char ch = getchar() ;
while( ch < '0' || ch > '9' ) ch = getchar() ;
while( ch >='0' && ch <='9' ) x = ( x << 1 ) + ( x << 3 ) + ch - '0' , ch = getchar() ;
}
int main(){
scanf( "%d%d" , &N , &M ) ;
for( int i = 1 ; i <= N ; i ++ )
read_( val[i] ) , val[i] ++ ;//权值全部+1, 最后答案-1, 方便分块
for( int i = 1 , u , v ; i < N ; i ++ ){
read_( u ) ; read_( v ) ;
In( u , v ) ; In( v , u ) ;
}
for( int i = 1 , opt , u , v ; i <= M ; i ++ ){
read_( opt ) , read_( u ) , read_( v ) ;
if( opt == 0 )
m[++mcnt] = ( Modifies ){ u , v + 1 , val[u] , i } , val[u] = v + 1 ;// Notice here !!!
else
q[++qcnt] = ( Queries ){ u , v , i } ;
}
m[mcnt+1].tim = 0x3f3f3f3f ;
for( int i = mcnt ; i ; i -- )
val[ m[i].pos ] = m[i].pre ;
init() ;
solve() ;
}