旅行

来源:互联网 发布: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才能联通,则现在有多少对城市能够联通 这样看起来就清晰了许多。
而且数据很大,题中也提示了需要选择适当的类型存储。这样很自然的想到可以用并查集来搞一下:

  • 维护连通性
  • 维护路径数
  • 维护边联通点数

下面介绍一下解决本题所需要用到的数组即他们的意义:

  1. fa[i]表示i的父节点
  2. s[i]表示以i为根联通点的个数
  3. 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];*/ 
0 0
原创粉丝点击