ABC.173.F - Intervals on Tree

传送门

题意:给定 n n n个结点 n − 1 n-1 n1条边的树,求结点的所有子集 ( 区 间 [ l , r ] ) (区间[l,r]) ([l,r])的连通块的和。

思路:考虑最开始为 n n n个孤立点的所有子集的连通块的和,再减去每条边对于连通块的贡献。

显然每个点就是一个连通块。

考虑包含 1 1 1的子集(区间): l ≤ 1 , r ≥ 1 l\leq1,r\geq1 l1,r1 l l l有1种选择, r r r n − 1 + 1 n-1+1 n1+1种选择。

1 × ( n − 1 + 1 ) = n 1\times(n-1+1)=n 1×(n1+1)=n种选择。

包含 2 2 2子集(区间): l ≤ 2 , r ≥ 2 l\leq2,r\geq2 l2,r2 l l l 2 2 2种选择, r r r n − 2 + 1 n-2+1 n2+1种选择。

2 × ( n − 2 + 1 ) = 2 × ( n − 1 ) 2\times(n-2+1)=2\times(n-1) 2×(n2+1)=2×(n1)

依次类推:

可得总连通块数:

∑ i = 1 n i × ( n − i + 1 ) = ( n + 1 ) × ∑ i = 1 n i − ∑ i = 1 n i 2 = ( n + 1 ) × n ( n + 1 ) 2 − n ( n + 1 ) ( 2 n + 1 ) 6 = n ( n + 1 ) ( 3 n + 3 − ( 2 n + 1 ) ) 6 = n ( n + 1 ) ( n + 2 ) 6 \sum\limits_{i=1}^ni\times(n-i+1)\\=(n+1)\times\sum\limits_{i=1}^ni-\sum\limits_{i=1}^ni^2\\=(n+1)\times \dfrac{n(n+1)}{2}-\dfrac{n(n+1)(2n+1)}{6}\\=\dfrac{n(n+1)(3n+3-(2n+1))}{6}\\=\dfrac{n(n+1)(n+2)}{6} i=1ni×(ni+1)=(n+1)×i=1nii=1ni2=(n+1)×2n(n+1)6n(n+1)(2n+1)=6n(n+1)(3n+3(2n+1))=6n(n+1)(n+2)

显然对于边 ( u , v ) (u,v) (u,v),(假设 u < v u<v u<v,因为区间 l ≤ r l\leq r lr),显然包含边 ( u , v ) (u,v) (u,v)的子集(区间)。

l ≤ u , r ≥ v l\leq u,r\geq v lu,rv,一共 u × ( n − v + 1 ) u\times(n-v+1) u×(nv+1)个子集,每个子集因为 u , v u,v u,v的相连会把 u , v u,v u,v两个连通块减为 1 1 1个。所以答案要减去 u × ( n − v + 1 ) u\times(n-v+1) u×(nv+1)

所以一边读入一边减去贡献即可。

时间复杂度: O ( n ) O(n) O(n)

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e5+5,M=1e6+5,inf=0x3f3f3f3f,mod=1e9+7;
#define mst(a) memset(a,0,sizeof a)
#define lx x<<1
#define rx x<<1|1
#define reg register
#define PII pair<int,int>
#define fi first 
#define se second
int main(){
	int n;
	scanf("%d",&n);
	ll ans=1LL*n*(n+1)*(n+2)/6;
	for(int i=1;i<n;i++){
		int u,v;
		scanf("%d%d",&u,&v);
		if(u>v) swap(u,v);
		ans-=1LL*u*(n-v+1); 
	}
	printf("%lld\n",ans); 
	return 0;
}