导航

HDU 3938

Posted on 2015-05-20 21:41  tun~  阅读(198)  评论(0编辑  收藏  举报

并查集的离线算法。

题意是大坑。理解为寻找两点之间所有路径中的最长的边的值小于输入的值的点对的个数。

直接来代码。

#include<stdio.h>
#include<iostream>
#include<algorithm>
using namespace std;
struct ab
{
    int a,b,c;
};
int n;
struct ab poi[50050];
struct cd
{
    int id,num,cc;
};
struct cd li[50050];
int me[50050];
int numb[50050];
bool cmp1(struct ab a,struct ab b)
{
    return a.c<b.c;
}
bool cmp2(struct cd a,struct cd b)
{
    return a.id<b.id;
}
bool cmp3(struct cd a,struct cd b)
{
    return a.num<b.num;
}
void link(int a,int b)
{
    me[b]=a;
    numb[a]+=numb[b];
}
int findme(int a)
{
    if(a!=me[a])
        return me[a]=findme(me[a]);
    return me[a];
}
int main()
{
    int m,q,i,j,k,ans,tmpa,tmpb;
    while(scanf("%d%d%d",&n,&m,&q)!=EOF)
    {
        for(i=1;i<=n;i++)
        {
            me[i]=i;
            numb[i]=1;
        }
        for(i=0;i<m;i++)
        {
            scanf("%d%d%d",&poi[i].a,&poi[i].b,&poi[i].c);
        }
        sort(poi,poi+m,cmp1);
        for(i=0;i<q;i++)
        {
            scanf("%d",&li[i].id);
            li[i].num=i;
        }
        sort(li,li+q,cmp2);
        j=0;
        ans=0;
        for(i=0;i<q;i++)
        {
            for(;j<m;j++)
            {
                if(poi[j].c>li[i].id)
                {
                    break;
                }
                else
                {
                    tmpa=findme(poi[j].a);
                    tmpb=findme(poi[j].b);
                    if(tmpa!=tmpb)
                    {
                        ans+=numb[tmpa]*numb[tmpb];
                        link(tmpa,tmpb);
                    }
                }
            }
            li[i].cc=ans;
        }
        sort(li,li+q,cmp3);
        for(i=0;i<q;i++)
        {
            printf("%d\n",li[i].cc);
        }
    }
    return 0;
}