hdu 离线处理+并查集

来源:互联网 发布:天下武功出少林 知乎 编辑:程序博客网 时间:2024/04/27 16:14

给你力量L,求有多少条path的力量小于等于L。

这个path消耗的力量是T,T是U到V上最长的边。

所以说,只要求得有多少个点对使得点对之间的最大的边小于L即可。

采用并查集,离线计算,询问从小到大排序,然后边从小到大排序,然后一个一个加入并查集中,加一条,计算一次两个集合的点的数目的乘积即可。

#include <iostream>#include <cmath>#include <cstdio>#include <string>#include <cstring>#include <algorithm>#include <vector>#include <queue>#include <utility>#define inf (1<<28)#define ll long long#define lson l,m,rt<<1#define rson m+1,r,rt<<1|1#define mid ((l+r)>>1)using namespace std;const int N=10010;const int M=50002;struct Node {    int u,v,len;}edge[M];int cmp(Node a,Node b){return a.len<=b.len;}int fa[N],sum[N];int n,m,q;void init(){    for(int i=1;i<=n;i++){fa[i]=i;sum[i]=1;}}int findx(int x){    return fa[x]=fa[x]==x?x:findx(fa[x]);}int Union(int a,int b){    int aa=findx(a);    int bb=findx(b);    //if(aa==bb)return 0;    if(fa[aa]<fa[bb])    {        fa[bb]=aa;        int tmp=sum[aa]*sum[bb];        sum[aa]+=sum[bb];        //cout<<" ____"<<tmp<<endl;        return tmp;    }    else {        fa[aa]=bb;        int tmp=sum[aa]*sum[bb];        sum[bb]+=sum[aa];        //cout<<" ____"<<tmp<<endl;        return tmp;    }}int ans[N];struct Q{    int L,id,ans;}que[N];bool cmp1(Q a,Q b){return a.L<=b.L;}bool cmp2(Q a,Q b){return a.id<b.id;}int main(){    while(scanf("%d%d%d",&n,&m,&q)!=EOF){        init();        for(int i=0;i<m;i++)scanf("%d%d%d",&edge[i].u,&edge[i].v,&edge[i].len);        for(int i=0; i<q; i++)            {scanf("%d",&que[i].L);que[i].id=i;que[i].ans=0;}        sort(edge,edge+m,cmp);        sort(que,que+q,cmp1);        int cnt=0;        for(int i=0;i<q;i++){            while(edge[cnt].len<=que[i].L&&cnt<m)            {                int aa=findx(edge[cnt].u);                int bb=findx(edge[cnt].v);                if(aa==bb)                {                    cnt++;                    continue;                }                else{                    //cout<<"------------"<<sum[aa]<<" "<<sum[bb]<<endl;                    que[i].ans+=Union(edge[cnt].u,edge[cnt].v);cnt++;                    //cout<<Union(edge[i].u,edge[i].v)<<endl;                }            }            if(i>=1)que[i].ans+=que[i-1].ans;//这里之前放在循环里面调了好久。。。        }        sort(que,que+q,cmp2);//还原之前的序列        for(int i=0; i<q; i++)        {           printf("%d\n",que[i].ans);        }    }    return 0;}
0 0
原创粉丝点击