[NOIP2017模拟]树
来源:互联网 发布:我的世界ipad枪械js 编辑:程序博客网 时间:2024/05/21 06:24
题目背景
SOURCE:NOIP2015-HN-CJZX
题目描述
树(tree)是指由 n 个点,n-1 条边构成的连通无向图。如果有一棵树,它的每一条边 (u,v) 都有一个权值
我们知道对于树上的任意两个点,他们之间的路径是唯一的。对于两个点 u,v 来说,我们可以算出 u 与 v 之间的路径上所有边权之和,将其称作 u 与 v 之间路径的长度,记作 d(u,v)。
你的任务是计算:
输入格式
输入第一行为一个正整数 n 。
接下来 n-1 行,每行三个非负整数 x,y,w,表示点 x 与点 y 之间有一条权值为 w 的一条边。
保证输入的图是一棵树。
输出格式
输出仅包含一行一个数,即答案。因为结果可能很大,请将答案模 100 000 007 输出。
样例数据 1
输入
4
1 2 4
1 3 4
1 4 4
输出
72
样例数据 2
输入
10
1 2 1320321
2 3 4687651
3 4 1321357
4 5 6651332
5 6 5746513
6 7 5674687
7 8 7451216
8 9 7789965
9 10 8765134
输出
28244404
备注
【样例1说明】
d(1,2)+d(1,3)+d(1,4)=4+4+4=12
d(2,1)+d(2,3)+d(2,4)=4+8+8=20
d(3,1)+d(3,2)+d(3,4)=4+8+8=20
d(4,1)+d(4,2)+d(4,3)=4+8+8=20
所以答案为:12+20+20+20=72。
【数据范围】
共 20 个测试点,其数据特征如下表所示。
对所有数据,有
分析:对于每一条边,使用的次数相当于这条边两边两块中的点数的乘积(左右每两个点都要计算距离对吧)再乘二(双向算距离),所以只需要知道每条边两边有多少点就行了,用个dfs预处理每一棵子树中的点的个数,连接这棵子树的边就要用size[子树点]*size[子树以外的点]次。
代码
#include<iostream>#include<cstdio>#include<cstdlib>#include<cstring>#include<string>#include<ctime>#include<cmath>#include<algorithm>#include<cctype>#include<iomanip>#include<queue>#include<set>using namespace std;int getint(){ int f=1,sum=0; char ch; for(ch=getchar();(ch<'0'||ch>'9')&&ch!='-';ch=getchar()); if(ch=='-') { f=-1; ch=getchar(); } for(;ch>='0'&&ch<='9';ch=getchar()) sum=(sum<<3)+(sum<<1)+ch-48; return sum*f;}const int maxn=300010;const int mo=100000007;struct node{ long long w; int fro,to;}bian[maxn];int tot,n;int first[maxn],nxt[maxn*2],to[maxn*2],size[maxn];long long ans;bool visit[maxn];void addedge(int x,int y,int z){ tot++; nxt[tot]=first[x]; first[x]=tot; to[tot]=y; tot++; nxt[tot]=first[y]; first[y]=tot; to[tot]=x;}void dfs(int u)//计算子树点数{ for(int p=first[u];p;p=nxt[p]) { int v=to[p]; if(!visit[v]) { visit[v]=1; dfs(v); visit[v]=0; size[u]+=size[v]; } }}int main(){ freopen("tree.in","r",stdin); freopen("tree.out","w",stdout); n=getint(); for(int i=1;i<=n;++i) size[i]=1;//子树包含子树的根节点 int x,y,z; for(int i=1;i<n;++i) { x=getint();y=getint();z=getint(); bian[i].fro=x;bian[i].to=y,bian[i].w=z;//不要问我为什么要赋两遍值,只是考试的时候傻了罢了 addedge(x,y,z); } visit[1]=1; dfs(1); for(int i=1;i<n;++i) if(size[bian[i].fro]>size[bian[i].to])//还是要判断一下谁是父亲,不然size就找错了 ans=(ans+(bian[i].w*size[bian[i].to]*(size[1]-size[bian[i].to]))%mo)%mo; else ans=(ans+(bian[i].w*size[bian[i].fro]*(size[1]-size[bian[i].fro]))%mo)%mo; ans=(ans*2)%mo;//乘二的工作最后来 cout<<ans<<'\n'; return 0;}
本题结。
- [NOIP2017模拟]树
- [NOIP2017模拟]树
- NOIP2017模拟 拆墙 (最大生成树)
- NOIP2017模拟赛1
- NOIP2017模拟赛8
- NOIP2017模拟赛9
- [NOIP2017模拟]切蛋糕
- [NOIP2017模拟]随机图
- [NOIP2017模拟]能源
- [NOIP2017模拟]电影
- [NOIP2017模拟]鸭舌
- [NOIP2017模拟]permut
- [NOIP2017模拟]beautiful
- [NOIP2017模拟]路径
- [NOIP2017模拟]流
- [NOIP2017模拟]subset
- [NOIP2017模拟]hello
- [NOIP2017模拟]table
- Java循环打印数组
- 二分查找
- Runtime类
- Hive中的简单窗口函数应用(TOPN)
- 面试OR笔试44——实现智能指针
- [NOIP2017模拟]树
- uva 10600 次小生成树
- CSS position 属性
- 9-23面试
- 设计模式-迭代器模式
- Matlab中,一种用脚本自动配置Simulink模型设置的方法
- strcmp()字符串比较函数
- 机房收费系统—细节优化
- 为ListView的最后一行添加分割线