码迷,mamicode.com
首页 > 其他好文 > 详细

并查集+二分 旅行

时间:2015-07-04 16:50:22      阅读:81      评论:0      收藏:0      [点我收藏+]

标签:

题目描述:

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 对于询问的结果可能很大,请注意使用适当的类型存储。


题解:

对于任意两点之间来说,起作用的只有崎岖度最小的的那条链上的最长边;

所以考虑维护这样的边与图的关系;

对边从小到大排序,然后维护一个连通性的并查集;

那么如果令f[i]为忍耐度为第i小的边时的答案的话;

可以得到转移方程f[i]=f[i-1]-size[x]*(size[x]-1)/2-size[y]*(size[y]-1)/2+(size[x]+size[y])*(size[x]+size[y]-1)/2;

size[x]表示x所在连通块中的点数;

然后为了快速的处理询问,可以做一些预处理;

使边权和f数组下标相对应,这样就可以通过二分边权数组来得到答案;

时间复杂度O(mlogm+Qlogm);


代码:


#include<stdio.h>
#include<string.h>
#include<algorithm>
#define N 110000
using namespace std;
typedef long long ll;
struct node
{
    int x,y,val;
}a[N<<1];
int f[N],len[N<<1];
ll ans[N<<1],size[N];
int find(int x)
{
    if(f[x]==x)
        return x;
    f[x]=find(f[x]);
    size[f[x]]+=size[x];
    size[x]=0;
    return f[x];
}
ll mul(ll x)
{
    return x*(x-1)/2;
}
int cmp(node a,node b)
{
    return a.val<b.val;
}
int main()
{
    int n,m,q,i,j,k,x,y,fx,fy;
    scanf("%d%d%d",&n,&m,&q);
    for(i=1;i<=m;i++)
        scanf("%d%d%d",&a[i].x,&a[i].y,&a[i].val);
    for(i=1;i<=n;i++)
        f[i]=i,size[i]=1;
    sort(a+1,a+1+m,cmp);
    for(i=1;i<=m;i++)
    {
        x=a[i].x,y=a[i].y;
        len[i]=a[i].val;
        fx=find(x),fy=find(y);
        if(fx!=fy)
        {
            ans[i]=ans[i-1]-mul(size[fy])-mul(size[fx])+mul(size[fx]+size[fy]);
            f[fx]=fy;
            size[fy]+=size[fx];
            size[fx]=0;
        }
        else
            ans[i]=ans[i-1];
    }
    for(i=1;i<=q;i++)
    {
        scanf("%d",&k);
        printf("%lld\n",ans[upper_bound(len+1,len+1+m,k)-len-1]);
    }
    return 0;
}



并查集+二分 旅行

标签:

原文地址:http://blog.csdn.net/ww140142/article/details/46755435

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!