P8290 [省选联考 2022] 填树

先考虑第一问:

\(V_k(L)\) 为权值在 \([L,L+k]\) 中的答案。

注意到当极差为 \(d\) 时贡献会计算 \(k-d+1\) 次,利用这个特点答案可以表示为 \(\sum_{L}V_k(L)-V_{k-1}(L)\) , 下面不妨省去 \(k\)

一条路径上的 \(V\) 为所有结点 \(V_i\) 的积,我们单独考察一下:

\[V_i(L)=\max(0,\min(r_i,L+k)-\max(l_i,L)+1) \]

  1. \(l_i+k \le r_i\)

\[V_i(L)=\begin{cases} 0 & (-\infty,l_i-k) \cup (r_i,+\infty) \\ k+1 & [l_i,r_i-k] \\ L+k-l_i+1 & [l_i-k,l_i) \\ -L+r_i+1 & (r_i-k,r_i] \end{cases} \]

  1. \(l_i+k > r_i\)

\[V_i(L)=\begin{cases} 0 & (-\infty,l_i-k) \cup (r_i,+\infty) \\ r_i-l_i+1 & [r_i-k,l_i] \\ L+k-l_i+1 & [l_i-k,r_i-k) \\ -L+r_i+1 & (l_i,r_i] \end{cases} \]

也就是说,值域被 \(l_i,l_i-k,r_i,r_i-k\) 划分为若干区间,且每个区间上的 \(V(L)\) 为一个不超过 \(n\) 次的多项式

那么 \(\displaystyle \sum_L V(L)\) 应为一个不超过 \(n+1\) 次的多项式

这样的划分点有 \(\mathcal O(n)\) 个,每个区间我们利用 换根dp \(\mathcal O(n^2)\) 求出前 \(n+2\) 项然后插值即可。

下面介绍一下换根 dp 的方法,这也是 40 分做法:

首先钦定 \(1\) 为根,令 \(f_u\) 表示以 \(u\) 子树内的点作为起点,\(\sum_{v} \prod_{i \in \{v \to u\}} V_i(L)\) 的值,易得:

\[f_u=(1+\sum_{v}f_v)V_u(L) \]

与此同时,我们需要知道每个点为起点时所有路径的权值和 \(g_i\),有:

\[g_v=f_v+(g_u-f_vV_u(L))V_v(L) \]

注意路径被计算了两次,单点只被计算了一次,所以有:

\[V(L)=\frac{1}{2}\left(\sum_{i=1}^n g_i+V_i(L)\right) \]


再考虑第二问,由于权值的贡献为和的形式所以我们考虑对每一个点单独计算贡献。

类似 \(V\) , 定义 \(W_i(L)=\max(0,\frac{1}{2}(\min(r_i,L+k)-\max(l_i,L)+1)(\max(l_i,L)+\min(r_i,L+k)))\) ,含义即为 \(i\)\([L,L+k]\) 中的取值之和。

再定义 \(h_u\) 表示经过 \(u\) 的路径条数(需要确定其他点权值),那么答案可以写作:

\[\sum_{L}\sum_{u}W_u(L) h_u \]

\(h\) 的定义与 \(f,g\) 的差异在于 \(u\) 的权值已经被钦定,为了对应定义 \(f_{2_u}=\frac{f_u}{V_u(L)},g_{2_u}=\frac{g_u}{V_u(L)}\)

\[h_u=\frac{1}{2}({g_{2_u}}^2-\sum_{(u,v)\in G}{f'_v}^2+1) \]

注意 \(f'_v\) 的含义是以 \(u\) 为根的 \(f_v\),那么有两种情况:

  1. \(v\) 在以 \(1\) 为根的树中为 \(u\) 的儿子,此时 \(f_v'=f_v\)

  2. \(v\) 在以 \(1\) 为根的树中为 \(u\) 的父亲,此时 \(f_v'=g_v -f_u V_v(L)\)

事实上 \({g_{2_u}}^2\)\(n-1\) 次式,那么 \(h_u\)\(n-1\) 次式
\(\sum_{L}W_u(L)h_u\)\(n+2\) 次式。


总的时间复杂度即为 \(\mathcal O(n^3)\)需要精细实现

卡常方面技不如人,附上在 loj 上能过的代码:

#include <cstdio>
#include <vector>
#include <iostream>
#include <algorithm>
using namespace std;
#define pii pair< int , int >
#define fi first
#define sc second
#define mp make_pair

template<typename _T>
void read( _T &x ) {
    x = 0; char s = getchar();
    for( ; s < '0' || s > '9' ; s = getchar() );
    for( ; s >= '0' && s <= '9' ; s = getchar() ) x = x * 10 + s - '0';
}
int pb , buf[ 100 ];
template<typename _T>
void write( _T x , char ed = '\n' ) {
    if( x == 0 ) buf[ ++ pb ] = 0;
    for( ; x ; x /= 10 ) buf[ ++ pb ] = x % 10;
    for( ; pb ; pb -- ) putchar( buf[ pb ] + '0' );
    putchar( ed );
}

const int MAXN = 205 , Mod = 1e9 + 7;
inline int Add( int x , int y ) { x += y; return x >= Mod ? x - Mod : x; }
inline int Sub( int x , int y ) { x -= y; return x < 0 ? x + Mod : x; }
inline int Mul( int x , int y ) { return 1ll * x * y % Mod; }
template<typename ...Args> inline int Mul( int x , Args ...args ) { return Mul( x , Mul( args... ) ); }
inline int Qkpow( int x , int po ) { int p = 1; for( ; po ; po >>= 1 , x = Mul( x , x ) ) if( po & 1 ) p = Mul( p , x ); return p; }
inline int Inv( int x ) { return Qkpow( x , Mod - 2 ); }
int fac[ MAXN + 5 ] , ivf[ MAXN + 5 ];
void Init( ) {
    fac[ 0 ] = 1;
    for( int i = 1 ; i <= MAXN ; i ++ ) fac[ i ] = Mul( fac[ i - 1 ] , i );
    ivf[ MAXN ] = Inv( fac[ MAXN ] );
    for( int i = MAXN ; i >= 1 ; i -- ) ivf[ i - 1 ] = Mul( ivf[ i ] , i );
}

pii operator + ( pii a , pii b ) { return mp( Add( a.fi , b.fi ) , Add( a.sc , b.sc ) ); }
pii operator - ( pii a , pii b ) { return mp( Sub( a.fi , b.fi ) , Sub( a.sc , b.sc ) ); }

int px[ MAXN + 5 ] , sx[ MAXN + 5 ];
int Lagrange( int n , int *y , int L , int x0 ) {
    if( x0 - L + 1 <= n ) return y[ x0 - L + 1 ];
    px[ 0 ] = 1; sx[ n + 1 ] = 1;
    for( int i = 1 ; i <= n ; i ++ ) px[ i ] = Mul( px[ i - 1 ] , Sub( x0 , Add( L , i - 1 ) ) );
    for( int i = n ; i >= 1 ; i -- ) sx[ i ] = Mul( sx[ i + 1 ] , Sub( x0 , Add( L , i - 1 ) ) );

    int ans = 0;
    for( int i = 1 ; i <= n ; i ++ )
        ans = Add( ans , Mul( y[ i ] , px[ i - 1 ] , sx[ i + 1 ] , ivf[ i - 1 ] , ( n - i ) & 1 ? Sub( 0 , ivf[ n - i ] ) : ivf[ n - i ] ) );
    return ans;
}

int n , K , l[ MAXN + 5 ] , r[ MAXN + 5 ];
vector< int > Graph[ MAXN + 5 ];

int gs , f[ MAXN + 5 ] , g[ MAXN + 5 ] , f2[ MAXN + 5 ] , g2[ MAXN + 5 ] , par[ MAXN + 5 ];
int V1[ MAXN + 5 ] , V2[ MAXN + 5 ];
void dfs1( int u , int fa ) {
    f[ u ] = 1; par[ u ] = fa;
    for( int v : Graph[ u ] ) if( v != fa )
        dfs1( v , u ) , f[ u ] = Add( f[ u ] , f[ v ] );
	f2[ u ] = f[ u ]; f[ u ] = Mul( f[ u ] , V1[ u ] );
}
void dfs2( int u , int fa ) {
    gs = Add( gs , Add( g[ u ] , V1[ u ] ) );
    for( int v : Graph[ u ] ) if( v != fa ) {
        g[ v ] = Add( f[ v ] , Mul( Sub( g[ u ] , Mul( f[ v ] , V1[ u ] ) ) , V1[ v ] ) );
        g2[ v ] = Add( f2[ v ] , Sub( g[ u ] , Mul( f[ v ] , V1[ u ] ) ) );
        dfs2( v , u );
    }
}

const int iv2 = Inv( 2 );

int m , d[ 4 * MAXN + 5 ] , y_1[ MAXN + 5 ] , y_2[ MAXN + 5 ];
pii Solve( int k ) {
    m = 0;
    for( int i = 1 ; i <= n ; i ++ )
        d[ ++ m ] = l[ i ] - k , d[ ++ m ] = l[ i ],
        d[ ++ m ] = r[ i ] - k , d[ ++ m ] = r[ i ];
    sort( d + 1 , d + m + 1 ); m = unique( d + 1 , d + m + 1 ) - d - 1;
    d[ m ] ++;

    pii ans( 0 , 0 );
    for( int i = 1 ; i < m ; i ++ ) { //[di,di+1)
        int L = d[ i ] , R = d[ i + 1 ] - 1;

        for( int j = L ; j <= min( R , L + n + 2 ) ; j ++ ) {
        	gs = 0;
			for( int u = 1 ; u <= n ; u ++ )
        		V1[ u ] = max( 0 , min( j + k , r[ u ] ) - max( j , l[ u ] ) + 1 ),
				V2[ u ] = max( 0 , (int)( 1ll * ( min( j + k , r[ u ] ) - max( j , l[ u ] ) + 1 ) * ( min( j + k , r[ u ] ) + max( j , l[ u ] ) ) / 2 % Mod ) );

            dfs1( 1 , 0 ); g[ 1 ] = f[ 1 ]; g2[ 1 ] = f2[ 1 ]; dfs2( 1 , 0 );
            y_1[ j - L + 1 ] = Add( y_1[ j - L ] , Mul( gs , iv2 ) );
            y_2[ j - L + 1 ] = y_2[ j - L ];
			
            for( int u = 1 ; u <= n ; u ++ ) if( V1[ u ] ) {
                int S = Mul( g2[ u ] , g2[ u ] );
                for( int v : Graph[ u ] ) {
                    int d;
                    if( v == par[ u ] ) d = Mul( Sub( g2[ v ] , f[ u ] ) , V1[ v ] );
                    else d = f[ v ];
                    S = Sub( S , Mul( d , d ) );
            	}
                y_2[ j - L + 1 ] = Add( y_2[ j - L + 1 ] , Mul( V2[ u ] , Mul( S + 1 , iv2 ) ) );
            }
        }
        ans.fi = Add( ans.fi , Lagrange( n + 2 , y_1 , L , R ) );
        ans.sc = Add( ans.sc , Lagrange( n + 3 , y_2 , L , R ) );
    }
    return ans;
}

int main( ) {
    // freopen("tree.in","r",stdin);
    // freopen("tree.out","w",stdout);

    Init();
    read( n ); read( K ); 
    for( int i = 1 ; i <= n ; i ++ ) read( l[ i ] ) , read( r[ i ] );
    for( int i = 1 , u , v ; i < n ; i ++ ) {
    	read( u ); read( v );
        Graph[ u ].push_back( v );
        Graph[ v ].push_back( u );
    }
    pii ans = Solve( K ) - Solve( K - 1 );
    printf("%d\n%d\n", ans.fi , ans.sc );
    return 0;
}
posted @ 2022-05-20 21:53  chihik  阅读(81)  评论(0编辑  收藏  举报