C.路径计数:
有一个 n 个点 n−1 条无向边的树. 每条边的长度可能并不相同。
我们定义 dis(u,v) 为从点 u 到点 v所有边的长度之和.。
你需要求出满足dis(u,v) 为奇数的无序点对 (u,v) 的数量。
输入格式:
第一行为一个整数 n(2≤n≤105),表示树的点数
之后n−1行每行包括三个整数ui,vi,wi(1≤ui,vi≤n,ui=vi,1≤wi≤109), 表示一条 连接点ui 和点 vi 长度为 wi 的边 .
输出格式:
一个整数,表示答案。
输入样例 1:
5
1 2 1
1 3 1
2 4 1
2 5 2
输出样例 1:
6
输入样例 2:
10
5 7 1
10 3 1
4 2 5
5 1 7
4 9 10
1 4 5
8 7 6
5 10 5
6 9 4
输出样例 2:
25
样例说明
第一个样例中, 6 条无序点对为 (1,2),(1,3),(1,5),(2,4),(3,4),(4,5) 。
代码长度限制
100 KB
Java (javac)
时间限制
2000 ms
内存限制
256 MB
其他编译器
时间限制
1000 ms
内存限制
256 MB
解决思路:
作为新手小白的zxl实在不擅长写树图,所以直接套用的单源最短路径算法,需要注意的是不能使用循环去遍历每个点(会超时),因为求的是奇数点的个数,所以肯定是奇数+偶数(画图就能看出来),数据范围太大必须开longlong(下次不开小M是狗),废话不多说直接上代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int n;
ll ans=0;
ll ji=0;
ll d[200010];
vector<pair<ll,ll> > a[200010];
priority_queue<pair<ll,ll> > q;
int main(){
scanf("%d",&n);
for(int i=1;i<=n-1;i++){
int x,y,z;
scanf("%d%d%d",&x,&y,&z);
a[x].push_back(make_pair(y,z));
a[y].push_back(make_pair(x,z));
}
memset(d,1000000002,sizeof d);
int s=1;
d[s]=0;
q.push(make_pair(-d[s],s));
while(q.size()>0){
pair<int,int> u=q.top();
q.pop();
for(int i=0;i<a[u.second].size();i++){
pair<int,int> e=a[u.second][i];
if(d[e.first]>d[u.second]+e.second){
d[e.first]=d[u.second]+e.second;
if(d[e.first]%2!=0)
{
ji++;
}
q.push(make_pair(-d[e.first],e.first));
}
}
}
ans=ji*(n-ji);
cout<<ans<<endl;
return 0;
}