Description
定义全部由 组成的数字为幸运数字,给出一棵 个节点的树,每条边的有边权,边权为幸运数字的边称为幸运边,求三元组 的个数使得 到 路径上都至少有一条幸运边
Input
第一行一整数 表示节点数,之后 每行输入三个整数 表示 之间有一条边权为 的树边
Output
输出满足条件的三元组个数
Sample Input
4
1 2 4
3 1 2
1 4 7
Sample Output
16
Solution
对于一点 ,求出所有到 路径上有幸运边的点的个数 ,那么答案即为 ,考虑用不是幸运边的边建图,那么所有与 不是一个连通块的点到 的路径上必然有幸运边,用并查集维护一下连通块以及连通块点数即可
Code
#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<vector>
#include<queue>
#include<map>
#include<set>
#include<ctime>
using namespace std;
typedef long long ll;
typedef pair<int,int>P;
const int INF=0x3f3f3f3f,maxn=100005;
int n,fa[maxn],num[maxn];
int find(int x)
{
if(fa[x]==x)return x;
return fa[x]=find(fa[x]);
}
void unite(int x,int y)
{
x=find(x),y=find(y);
if(x==y)return ;
fa[x]=y;
num[y]+=num[x];
}
bool check(int x)
{
while(x)
{
if(x%10!=4&&x%10!=7)return 0;
x/=10;
}
return 1;
}
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++)fa[i]=i,num[i]=1;
int u,v,w;
for(int i=1;i<n;i++)
{
scanf("%d%d%d",&u,&v,&w);
if(!check(w))unite(u,v);
}
ll ans=0;
for(int i=1;i<=n;i++)
{
int t=n-num[find(i)];
ans+=(ll)t*(t-1);
}
printf("%I64d\n",ans);
return 0;
}