Portal 【HDU - 3938】【带权并查集+预处理】

题目链接


  题意:先建立M条边,然后查询在L能量下能走多少条边的走法,然后看到查询的个数与查询的权值,我们可以通过按权值升序来做一个优化。

  思路:我们要想知道所有符合条件的走法,可以先研究一下题目中给的样例中L==5时候的可能,会有这样的走法:

{1->2}、{2->7}、{1->7}、

{6->8}、{5->8}、{8->10}、{4->6}、{4->8}、{6->10}、{5->10}、{4->5}、{5->6}、{4->10}

这么几种走法,然后我们来推一下种类数与ans的关系,看到1、2、7这几个点的答案,种类可能是3,先把1连接到2上,可以看作2上的子节点多了一,然后这是方案一,然后把2连接到7上,7的子节点就有2个了,但是看前缀,相当于把2节点上的两个节点按两种方式连接到单一的7上,所以应当加的方案数是2*1==2。

按照上面的做法,我们推其他的可能,会发现所有的节点都符合这样的条件,加上去的边权为sum[根1]*sum[根2]。

  剩下的就是对于查询的L的按升序的处理了,自己思考吧,挺简单的,一半是惯用的思维。


#include <iostream>
#include <cstdio>
#include <cmath>
#include <string>
#include <cstring>
#include <algorithm>
#include <limits>
#include <vector>
#include <stack>
#include <queue>
#include <set>
#include <map>
#define lowbit(x) ( x&(-x) )
#define pi 3.141592653589793
#define e 2.718281828459045
using namespace std;
typedef unsigned long long ull;
typedef long long ll;
const int maxN=1e4+5;
int N, M, Q, root[maxN];
ll sum[maxN];
struct Eddge
{
    int no, to, val;
    Eddge(int a=0, int b=0, int c=0):no(a), to(b), val(c) {}
}edge[5*maxN];
bool cmp_ed(Eddge e1, Eddge e2) { return e1.val<e2.val; }
struct Query
{
    int ques, id;
    ll sum;
    Query(int a=0, int b=0, ll c=0):ques(a), id(b), sum(c) {}
}qq[maxN];
bool cmp_qu(Query e1, Query e2) { return e1.ques<e2.ques; }
bool cmp_qu2(Query e1, Query e2) { return e1.id<e2.id; }
void init()
{
    for(int i=1; i<=N; i++) { root[i]=i; sum[i]=1; }
}
int fid(int x) { return x==root[x]?x:(root[x]=fid(root[x])); }
ll mix(int x, int y)
{
    int u=fid(x), v=fid(y);
    if(u == v) return 0;
    ll ans=sum[u]*sum[v];
    if(sum[u]>sum[v]) swap(u, v);   //可有可无,爱好问题
    root[u]=v;
    sum[v]+=sum[u];
    return ans;
}
int main()
{
    while(scanf("%d%d%d", &N, &M, &Q)!=EOF)
    {
        for(int i=1; i<=M; i++)
        {
            scanf("%d%d%d", &edge[i].no, &edge[i].to, &edge[i].val);
        }
        sort(edge+1, edge+1+M, cmp_ed);
        for(int i=1; i<=Q; i++)
        {
            scanf("%d", &qq[i].ques);
            qq[i].id=i;
        }
        sort(qq+1, qq+1+Q, cmp_qu);
        init();
        int j=1;
        ll sum=0;
        for(int i=1; i<=M && j<=Q; )
        {
            if(qq[j].ques >= edge[i].val)
            {
                sum+=mix(edge[i].no, edge[i].to);
                i++;
            }
            else
            {
                qq[j++].sum=sum;
            }
        }
        while(j<=Q) { qq[j].sum=sum; j++; }
        sort(qq+1, qq+1+Q, cmp_qu2);
        for(int i=1; i<=Q; i++) printf("%lld\n", qq[i].sum);
    }
    return 0;
}

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Wuliwuliii

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值