版权声明:转载嘛....也不是不可以(故作沉思),记得带上me的ID啊qwq https://blog.csdn.net/Izumi_Hanako/article/details/80674376
说在前面
昨天看了一天置换群,感觉药丸
于是今天来刷一刷题
题目
BZOJ3631传送门
看题可戳传送门
解法
就相当于是链加,树上差分一下就好了
u++,v++
Lca-1,fa[Lca]-1
完了之后dfs统计一下,子树和就是答案
下面是代码
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std ;
int N , a[300005] , tp , head[300005] , lg_ ;
struct Path{
int pre , to ;
} p[600005] ;
void In( int t1 , int t2 ){
p[++tp] = ( Path ){ head[t1] , t2 } ; head[t1] = tp ;
p[++tp] = ( Path ){ head[t2] , t1 } ; head[t2] = tp ;
}
int dep[300005] , fa[20][300005] , maxd ;
void dfs_pre( int u , int f ){
for( int i = head[u] ; i ; i = p[i].pre ){
int v = p[i].to ;
if( v == f ) continue ;
fa[0][v] = u , dep[v] = dep[u] + 1 ;
dfs_pre( v , u ) ;
} maxd = max( maxd , dep[u] ) ;
}
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 = lg_ ; i >= 0 ; i -- )
if( fa[i][u] != fa[i][v] )
u = fa[i][u] , v = fa[i][v] ;
return fa[0][u] ;
}
void preWork(){
dfs_pre( 1 , 1 ) ;
for( lg_ = 1 ; ( 1 << ( lg_ + 1 ) ) <= maxd ; lg_ ++ ) ;
for( int i = 1 ; i <= lg_ ; i ++ )
for( int j = 1 ; j <= N ; j ++ )
fa[i][j] = fa[i-1][ fa[i-1][j] ] ;
}
int tag[300005] ;
void dfs( int u ){
for( int i = head[u] ; i ; i = p[i].pre ){
int v = p[i].to ;
if( v == fa[0][u] ) continue ;
dfs( v ) , tag[u] += tag[v] ;
}
}
void solve(){
for( int i = 2 ; i <= N ; i ++ ){
int LCA = Lca( a[i-1] , a[i] ) ;
tag[ a[i-1] ] ++ , tag[ fa[0][a[i]] ] ++ ;
tag[ LCA ] -- , tag[ fa[0][LCA] ] -- ;
} dfs( 1 ) ;
for( int i = 1 ; i <= N ; i ++ )
printf( "%d\n" , tag[i] ) ;
}
int main(){
scanf( "%d" , &N ) ;
for( int i = 1 ; i <= N ; i ++ )
scanf( "%d" , &a[i] ) ;
for( int i = 1 , u , v ; i < N ; i ++ )
scanf( "%d%d" , &u , &v ) , In( u , v ) ;
preWork() ; solve() ;
}