1. 程式人生 > >Hdu 3938 Portal【離線+並查集+思維】

Hdu 3938 Portal【離線+並查集+思維】

Portal

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 1792    Accepted Submission(s): 883


Problem Description ZLGG found a magic theory that the bigger banana the bigger banana peel .This important theory can help him make a portal in our universal. Unfortunately, making a pair of portals will cost min{T} energies. T in a path between point V and point U is the length of the longest edge in the path. There may be lots of paths between two points. Now ZLGG owned L energies and he want to know how many kind of path he could make.
Input There are multiple test cases. The first line of input contains three integer N, M and Q (1 < N ≤ 10,000, 0 < M ≤ 50,000, 0 < Q ≤ 10,000). N is the number of points, M is the number of edges and Q is the number of queries. Each of the next M lines contains three integers a, b, and c (1 ≤ a, b ≤ N, 0 ≤ c ≤ 10^8) describing an edge connecting the point a and b with cost c. Each of the following Q lines contain a single integer L (0 ≤ L ≤ 10^8).
Output Output the answer to each query on a separate line.
Sample Input 10 10 10 7 2 1 6 8 3 4 5 8 5 8 2 2 8 9 6 4 5 2 1 5 8 10 5 7 3 7 7 8 8 10 6 1 5 9 1 8 2 7 6
Sample Output 36 13 1 13 36 1 36 2 16 13

題目大意:

給出N個點,M條無向邊,以及Q個查詢,每個查詢詢問兩點間所有路徑上的最大值最小值為w,並且w<=Qi的點對數。

思路:

①我們首先思考,詢問兩點間所有路徑的最大值最小,其實就是在詢問,從點u到點v最短路徑上的最大值。那麼希望兩點間最短路徑最短,其實問題就相當於求一顆MST。

對應兩點間最短路的最大值,就是聯通點u和點v的最後一條邊的權值。

②那麼我們離線處理問題,將詢問按照從小到大排序,然後將每條邊按照權值從小到大排序,對於當前加入樹邊(u,v,w),對應ans【w】=sum【u】*sum【v】,這裡sum【u】表示的就是點u所在聯通塊點的個數。

③注意資料範圍,過程維護一下即可。

Ac程式碼:

#include<stdio.h>
#include<string.h>
#include<vector>
#include<algorithm>
using namespace std;
int f[1050000];
int sum[1050000];
long long int output[1050000];
struct node
{
    int x,y,w;
}a[1050000];
struct node2
{
    int val,pos;
}q[1050000];
int cmp(node a,node b)
{
    return a.w<b.w;
}
int cmp2(node2 a,node2 b)
{
    return a.val<b.val;
}
int find(int a)
{
    int r=a;
    while(f[r]!=r)
    r=f[r];
    int i=a;
    int j;
    while(i!=r)
    {
        j=f[i];
        f[i]=r;
        i=j;
    }
    return r;
}
void merge(int a,int b)
{
    int A,B;
    A=find(a);
    B=find(b);
    if(A!=B)
    {
        f[B]=A;
        sum[A]+=sum[B];
    }
}
int main()
{
    int n,m,qq;
    while(~scanf("%d%d%d",&n,&m,&qq))
    {
        for(int i=1;i<=n;i++)f[i]=i,sum[i]=1;
        for(int i=1;i<=m;i++)
        {
            scanf("%d%d%d",&a[i].x,&a[i].y,&a[i].w);
        }
        for(int i=1;i<=qq;i++)
        {
            scanf("%d",&q[i].val);q[i].pos=i;
        }
        sort(a+1,a+1+m,cmp);
        sort(q+1,q+1+qq,cmp2);
        long long int ans=0;
        int j=1;
        for(int i=1;i<=m;i++)
        {
            if(find(a[i].x)!=find(a[i].y))
            {
                while(j<=qq&&q[j].val<a[i].w)output[q[j].pos]=ans,j++;
                ans+=(long long int )sum[find(a[i].x)]*sum[find(a[i].y)];
                merge(a[i].x,a[i].y);
            }
        }
        while(j<=qq)output[q[j].pos]=ans,j++;
        for(int i=1;i<=qq;i++)
        {
            printf("%lld\n",output[i]);
        }
    }
}