旅行
来源:互联网 发布:mac office 转换成pdf 编辑:程序博客网 时间:2024/04/27 18:57
旅行
Time Limit: 1 Sec Memory Limit: 128 MB
Description
A国有n座城市,每座城市都十分美,这使得A国的民众们非常喜欢旅行。然而,A国的交通十分落后,这里只有m条双向的道路,并且这些道路都十分崎岖,有的甚至还是山路,只能靠步行。通过每条道路的长度、泥泞程度等因素,我们给每条道路评估一个“崎岖度”,表示通过这条道路的不舒适程度。
从X城市经过若干条道路到达Y城市,我们称这次旅行的“代价”为所经过道路“崎岖度”的最大值。当然,如果从X城市到Y城市有多条路线,民众们会自觉选择“代价”最小的路线进行旅行。但是,A国的民众也是有脾气的,如果旅行的“代价”超过了他们的“忍耐度”,他们就不选择这个旅行了,甚至宁愿在家里宅着。
现在A国的国王想进行若干次询问:给定民众的“忍耐度”,问还有多少对城市(X,Y)会存在旅行?请你对国王的每次询问分别给出回答。
Input
第1行三个正整数n、m、Q,分别表示城市数量、道路数量和询问次数。
第2行到第m+1行每行三个正整数x、y、w,表示x号城市和y号城市之间有一条“崎岖度”为w的双向道路。
第m+2行至第m+Q+1行,每行一个正整数k,表示询问中给定的“忍耐度”为k。
Output
共Q行,对于每次询问做出回答。
Sample Input
5 5 2
1 2 1
2 3 2
3 4 1
4 5 4
5 1 1
1
2
Sample Output
4
10
HINT
【样例说明】
第一个询问:(1,2)、(1,5)、(2,5)、(3,4)。其中(2,5)的具体走法为:2-1-5
第二个询问:(1,2)、(1,3)、(1,4)、(1,5)、(2,3)、(2,4)、(2,5)、(3,4)、(3,5)、(4,5)。其中(4,5)的具体走法为:4-3-2-1-5
【数据规模】
对于20%的数据满足n<=20,m<=40,Q<=40;
对于40%的数据满足n<=1000,m<=2000,Q<=1000;
对于60%的数据满足n<=3000,m<=6000,Q<=200000;
对于100%的数据满足n<=100000,m<=200000,Q<=200000。其他数不超过10^9。
【细节提示】
1 给出的n个城市不一定全部互相连通,且两个城市之间可能存在多条道路,也可能存在某条边是从某城市出发回到他自己。
2 对于询问的结果可能很大,请注意使用适当的类型存储。
并查集+二分查找
Aim:求有多少条路径,其最大值<=k,即存在多少(x,y)点对。
But!!这样会十分麻烦,比如说我第一次看到这道题就想到了NOIP2013 D1 T3的货车运输:在线搞一下LCA,然后n^2枚举所有点对,如果满足就累加。不过这样不超时才怪。。而且有种预感,肯定有更巧妙的方法。
所以,我们不妨转换一下思路,题意:若边权<=K才能联通,则现在有多少对城市能够联通 这样看起来就清晰了许多。
而且数据很大,题中也提示了需要选择适当的类型存储。这样很自然的想到可以用并查集来搞一下:
- 维护连通性
- 维护路径数
- 维护边联通点数
下面介绍一下解决本题所需要用到的数组即他们的意义:
- fa[i]表示i的父节点
- s[i]表示以i为根联通点的个数
- f[i]表示第i条边联通点的对数
举几个例子来理解一下这些数组的含义:
对于x,y来说,很显然y是x的父节点,同时s[x]=3;s[y]=3;
在利用并查集维护的时候在合并父节点的同时可以直接合并一下s[],对于上面的例子显然可以s[y]+=s[x];
但是f[i]并不好理解,先说一下转移:f[i]=之前联通的点对数+新联通的点对数
=>f[i-1]+s[t1]*s[t2]
( 对于每条边t1,t2分别表示这条边起点和终点的父节点 )
s[t1]*s[t2]也非常容易理解,即s[t1]中的所有点都能与s[t2]中的点相连通。
So,最后,我们需要找了。
为了查找方便,我们需要在进行上述操作前先按边权值升序排序,而上述操作实际上是在构造最小生成树。为了加速查找需要用到二分查找,姿势神马的就不用多强调了。最后找出Val<=k的最后一个边,此边联通的点对数就是我们需要的答案。
Code:
#include <stdio.h>#include <string.h>#include <algorithm>#define MAXN 205000using namespace std;struct node{ int from; int to; int val; int next;}edge[MAXN<<1];int n,m,q,k,cnt;int head[MAXN],fa[MAXN],s[MAXN],f[MAXN];int cmp(node a,node b){return a.val < b.val ? 1 : 0;}void init(){ memset(head,-1,sizeof(head)); cnt=1; for(int i=1;i<=n;i++) { fa[i]=i; s[i]=1; }}void addedge(int from,int to,int val){ edge[cnt].from=from; edge[cnt].to=to; edge[cnt].val=val; edge[cnt].next=head[from]; head[from]=cnt++;}int find(int v){ if(fa[v]!=v) { fa[v]=find(fa[v]); } s[v]=s[fa[v]]; return fa[v];}int search(int x){ int l=1,r=m,mid,ret; while(l<=r) { mid=(l+r)>>1; if(edge[mid].val<=x) { l=mid+1; ret=mid; } else r=mid-1; } return ret;}void print(){ while(q--) { scanf("%d",&k); printf("%d\n",f[search(k)]); }}int main(){ scanf("%d%d%d",&n,&m,&q); init(); for(int i=1;i<=m;i++) { int a,b,c; scanf("%d%d%d",&a,&b,&c); addedge(a,b,c); } sort(edge+1,edge+1+cnt,cmp); for(int i=1;i<=cnt;i++) { int t1=find(edge[i].from); int t2=find(edge[i].to); f[i]=f[i-1]; if(t1!=t2) { f[i]+=s[t1]*s[t2]; fa[t1]=t2; s[t2]+=s[t1]; } } print(); return 0;}/*时间复杂度为O[m*(log m)+q];*/
- 旅行
- 旅行
- 旅行...
- 旅行
- 旅行
- 旅行
- 旅行
- 旅行
- 旅行
- 旅行
- 旅行...
- 旅行
- 旅行
- 旅行
- 【旅行】
- 旅行
- 旅行
- 旅行
- java发送邮件(3)
- 线段树模板
- Android drawText获取text宽度的三种方式
- JAVA学习笔记1--类的成员以及继承
- I/O编程
- 旅行
- HDU 1533 (最小费用最大流)(spfa+ek或spfa+dinic)
- 【effective c++读书笔记】【第5章】实现(1)
- 《高质量程序设计指南C/C++语言 》 林锐,韩永泉编著 总结1
- Browser caching
- hdu 5078 Osu!
- HDU 4343 多查询求区间内的最大不相交区间个数-思维&贪心-卡时间&二分&剪枝
- Triangle
- 扫描二维码自动识别手机系统(Android/IOS)跳转不同页面