5055. 树上路径

来源:互联网 发布:淘宝店铺名称旗舰店 编辑:程序博客网 时间:2024/03/29 05:16

题目大意

给定一颗n个结点的无根树,每个点有一个点权,定义一条路径的价值为路径上的点权和-路径的点权最大值。
给定参数p,求有多少不同的树上简单路径,满足它的价值恰好是p的倍数。

Data Constraint
n105,p107

题解

考虑点分治。
对于当前的分治重心,把所有以它为起点的路径取出来,按照路径上点权的最大值排序。然后考虑如何计算答案。对于当前枚举到的第i条路径,前面i1条路径的最大值显然都小于等于当前这条,所以可以直接维护一个桶,每次在桶内查询即可。
注意要去掉一个子树内部的路径对答案的贡献。

时间复杂度:O(nlog2n)

SRC

#include<cstdio>#include<cstdlib>#include<cstring>#include<iostream>#include<algorithm>using namespace std ;#define N 100000 + 10#define M 10000000 + 10typedef 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 ;}

以上.

1 0
原创粉丝点击