P8290 [省选联考 2022] 填树

先考虑第一问:

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

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

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

Vi(L)=max(0,min(ri,L+k)max(li,L)+1)

  1. li+kri

Vi(L)={0(,lik)(ri,+)k+1[li,rik]L+kli+1[lik,li)L+ri+1(rik,ri]

  1. li+k>ri

Vi(L)={0(,lik)(ri,+)rili+1[rik,li]L+kli+1[lik,rik)L+ri+1(li,ri]

也就是说,值域被 li,lik,ri,rik 划分为若干区间,且每个区间上的 V(L) 为一个不超过 n 次的多项式

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

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

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

首先钦定 1 为根,令 fu 表示以 u 子树内的点作为起点,vi{vu}Vi(L) 的值,易得:

fu=(1+vfv)Vu(L)

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

gv=fv+(gufvVu(L))Vv(L)

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

V(L)=12(i=1ngi+Vi(L))


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

类似 V , 定义 Wi(L)=max(0,12(min(ri,L+k)max(li,L)+1)(max(li,L)+min(ri,L+k))) ,含义即为 i[L,L+k] 中的取值之和。

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

LuWu(L)hu

h 的定义与 f,g 的差异在于 u 的权值已经被钦定,为了对应定义 f2u=fuVu(L),g2u=guVu(L)

hu=12(g2u2(u,v)Gfv2+1)

注意 fv 的含义是以 u 为根的 fv,那么有两种情况:

  1. v 在以 1 为根的树中为 u 的儿子,此时 fv=fv

  2. v 在以 1 为根的树中为 u 的父亲,此时 fv=gvfuVv(L)

事实上 g2u2n1 次式,那么 hun1 次式
LWu(L)hun+2 次式。


总的时间复杂度即为 O(n3)需要精细实现

卡常方面技不如人,附上在 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 @   chihik  阅读(92)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· 【杂谈】分布式事务——高大上的无用知识?
点击右上角即可分享
微信分享提示