题目大意
给定一颗
n
个结点的无根树,每个点有一个点权,定义一条路径的价值为路径上的点权和-路径的点权最大值。
给定参数
Data Constraint
题解
考虑点分治。
对于当前的分治重心,把所有以它为起点的路径取出来,按照路径上点权的最大值排序。然后考虑如何计算答案。对于当前枚举到的第
i
条路径,前面
注意要去掉一个子树内部的路径对答案的贡献。
时间复杂度: O(nlog2n)
SRC
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std ;
#define N 100000 + 10
#define M 10000000 + 10
typedef long long ll ;
struct Note {
int Maxv , Sum ;
Note ( int X = 0 , int Y = 0 ) { Maxv = X , Sum = Y ; }
} D[N] , tp[N] ;
bool vis[N] ;
int Node[2*N] , Next[2*N] , Head[N] , tot ;
int val[N] , Size[N] , Maxs[N] , T[M] ;
int n , MO ;
int Root , All , Minv , Cnt , Num ;
ll ans ;
bool cmp( Note a , Note b ) { return a.Maxv < b.Maxv ; }
void link( int u , int v ) {
Node[++tot] = v ;
Next[tot] = Head[u] ;
Head[u] = tot ;
}
void GetSize( int x , int F ) {
Size[x] = Maxs[x] = 1 ;
for (int p = Head[x] ; p ; p = Next[p] ) {
if ( Node[p] == F || vis[Node[p]] ) continue ;
GetSize( Node[p] , x ) ;
Size[x] += Size[Node[p]] ;
Maxs[x] = max( Maxs[x] , Size[Node[p]] ) ;
}
}
void GetRoot( int x , int F ) {
Maxs[x] = max( Maxs[x] , Size[All] - Maxs[x] ) ;
if ( Maxs[x] < Minv ) Minv = Maxs[x] , Root = x ;
for (int p = Head[x] ; p ; p = Next[p] ) {
if ( Node[p] == F || vis[Node[p]] ) continue ;
GetRoot( Node[p] , x ) ;
}
}
void DFS( int x , int F , int Maxv , int Sum ) {
D[++Cnt] = Note( Maxv , Sum ) ;
tp[++Num] = Note( Maxv , Sum ) ;
if ( (((Sum + val[Root]) % MO - max( Maxv , val[Root] )) % MO + MO) % MO == 0 ) ans ++ ;
for (int p = Head[x] ; p ; p = Next[p] ) {
if ( Node[p] == F || vis[Node[p]] ) continue ;
DFS( Node[p] , x , max( Maxv , val[Node[p]] ) , (Sum + val[Node[p]]) % MO ) ;
}
}
void Calc( Note *a , int n , int sig ) {
sort( a + 1 , a + n + 1 , cmp ) ;
for (int i = 1 ; i <= n ; i ++ ) {
if ( a[i].Maxv <= val[Root] ) ans += sig * T[MO-a[i].Sum] ;
else {
int s = (((a[i].Maxv - val[Root]) % MO - a[i].Sum) % MO + MO) % MO ;
ans += sig * T[s] ;
}
T[a[i].Sum] ++ ;
}
for (int i = 1 ; i <= n ; i ++ ) T[a[i].Sum] -- ;
}
void Solve( int x ) {
Root = All = x , Minv = 0x7FFFFFFF ;
GetSize( x , 0 ) ;
GetRoot( x , 0 ) ;
vis[Root] = 1 ;
Cnt = Num = 0 ;
for (int p = Head[Root] ; p ; p = Next[p] ) {
if ( vis[Node[p]] ) continue ;
Num = 0 ;
DFS( Node[p] , Root , val[Node[p]] , val[Node[p]] % MO ) ;
Calc( tp , Num , -1 ) ;
}
Calc( D , Cnt , 1 ) ;
for (int p = Head[Root] ; p ; p = Next[p] ) {
if ( vis[Node[p]] ) continue ;
Solve( Node[p] ) ;
}
}
int main() {
freopen( "path.in" , "r" , stdin ) ;
freopen( "path.out" , "w" , stdout ) ;
scanf( "%d%d" , &n , &MO ) ;
for (int i = 1 ; i < n ; i ++ ) {
int u , v ;
scanf( "%d%d" , &u , &v ) ;
link( u , v ) , link( v , u ) ;
}
for (int i = 1 ; i <= n ; i ++ ) scanf( "%d" , &val[i] ) ;
Solve(1) ;
printf( "%lld\n" , ans + n ) ;
return 0 ;
}
以上.