题解 CF109C Lucky Tree

Posted 苹果蓝17

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了题解 CF109C Lucky Tree相关的知识,希望对你有一定的参考价值。

题目传送门

题意简述

一棵树,其中有若干条关键边,求有多少点三元组 \\((i,j,k)\\) 满足 \\(i\\)\\(j\\) 间有关键边且 \\(i\\)\\(k\\) 间有关键边。

\\(n \\leq 10^5\\)

题目分析

同学说这题很有迷惑性。

考虑转化 \\(i\\)\\(j\\) 间有关键边的条件,很容易想到将所有关键边断开后会形成若干联通块 \\(t_1,t_2,\\cdots,t_k\\)

设点 \\(u\\) 所属的联通块为 \\(s_u\\),即 \\(u \\in s_u\\)

显然 \\(u\\)\\(v\\) 间有关键边当且仅当 \\(s_u \\neq s_v\\)

\\[\\begin{aligned} ans & =\\sum_{i \\neq j \\neq k} [s_i \\neq s_j][s_i \\neq s_k]\\\\ & =\\sum_{i} \\sum_{j \\neq k}[s_i \\neq s_j][s_i \\neq s_k]\\\\ & =\\sum_{i} 2\\dbinom{n-|s_i|}{2}\\\\ & =2\\sum_{i_1}^n \\dbinom{n-|s_i|}{2}\\\\ & =2\\sum_{i_1}^k |t_i| \\dbinom{n-|t_i|}{2}\\\\ \\end{aligned} \\]

dfs 计算联通块大小,组合数直接计算即可。

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

拓展 1:点带权。

\\(W=\\sum\\limits_{i=1}^n w_i\\)\\(W_k=\\sum\\limits_{i \\in s_k}^n w_i\\)(即该点所在联通块的点权和),\\(W_k=\\sum\\limits_{i \\in s_k}^n w_i^2\\)

\\[\\begin{aligned} ans & =\\sum\\limits_{i}w_i(\\sum\\limits_{j,k}[s_i \\neq s_j][s_i \\neq s_k]w_jw_k-\\sum\\limits_{j} [s_i \\neq s_j]w_j^2)\\\\ & =\\sum\\limits_i w_i[(W-W_i)^2-W_i\']\\\\ \\end{aligned} \\]

拓展 2:多元组。

若将条件改为 \\(p\\) 元组,且任意两点间有关键边,即为任意两点不同属一个联通块。

即从 \\(k\\) 个数里任意选出 \\(p\\) 个数的积之和。

这是一个经典问题,即 \\([x^p]\\prod_{i=1}^k (1+t_ix)\\),分治+FFT 即可在 \\(O(k\\log^2 k)\\) 的时间复杂度内解决。

代码

#include<bits/stdc++.h>
using namespace std;
const long long N=1e5+5;
struct nod{
	long long to,nxt,w;
}e[N*2];
long long head[N],cnt;
void add(long long u,long long v,long long w){
	e[++cnt].to=v;
	e[cnt].w=w;
	e[cnt].nxt=head[u];
	head[u]=cnt;
}
long long check(long long x){
	while(x){
		if(x%10!=4 && x%10!=7) return 0;
		x/=10;
	}
	return 1;
}
long long n,id,ans;
bool vis[N];
void dfs(long long u){
	vis[u]=1;
	id++;
	for(long long i=head[u];i;i=e[i].nxt){
		long long v=e[i].to;
		if(vis[v] || e[i].w) continue;
		dfs(v);
	}
}

int main(){
	cin>>n;
	for(long long i=1;i<n;i++){
		long long u,v,w;
		scanf("%lld%lld%lld",&u,&v,&w);
		long long t=check(w);
		add(u,v,t);
		add(v,u,t);
	}
	for(long long i=1;i<=n;i++){
		if(!vis[i]){
			id=0;
			dfs(i);
			ans+=id*(n-id)*(n-id-1);
		}
	}
	printf("%lld",ans);
}

以上是关于题解 CF109C Lucky Tree的主要内容,如果未能解决你的问题,请参考以下文章

codeforces 110E Lucky Tree

题解 CF375D Tree and Queries

题解 CF375D Tree and Queries

CF504E Misha and LCP on Tree 题解

CF771C Bear and Tree Jumps 题解

竞赛题解 - Broken Tree(CF-758E)