ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

P8290 [省选联考 2022] 填树

2022-05-20 22:00:34  阅读:142  来源: 互联网

标签:P8290 pii 省选 sum int Add MAXN Mul 联考


先考虑第一问:

令 \(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;
}

标签:P8290,pii,省选,sum,int,Add,MAXN,Mul,联考
来源: https://www.cnblogs.com/chihik/p/P8290.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有