返回顶部

The 15th Chinese Northeast Collegiate Programming Contest K. City (最小生成树计数,离线询问)

  • 题意:有一张\(n\)个点,\(m\)条边的无向图,每条边都有边权,\(q\)个询问,每次问一个\(q_i\),将所有边权减去\(p_i\)后不小于\(0\)的边为有效边,问有多少对点能相互到达。

  • 题解:一张图,两个点连通,不难想到最小生成树,进而想到保留边权最大的边最优,即转化成了最大生成树,那么我们就可以将询问离线存下来从小到大排序,然后跑kruskal同时二分找到满足条件的最大询问,贡献给对应询问的答案。最后再跑个后缀把空的位置填起来。

  • 代码:

    #include <bits/stdc++.h>
    #define ll long long
    #define fi first
    #define se second
    #define pb push_back
    #define me memset
    #define rep(a,b,c) for(int a=b;a<=c;++a)
    #define per(a,b,c) for(int a=b;a>=c;--a)
    const int N = 1e6 + 10;
    const int mod = 1e9 + 7;
    const int INF = 0x3f3f3f3f;
    using namespace std;
    typedef pair<int,int> PII;
    typedef pair<ll,ll> PLL;
    ll gcd(ll a,ll b) {return b?gcd(b,a%b):a;}
    ll lcm(ll a,ll b) {return a/gcd(a,b)*b;}
    
    #define int long long 
    
    struct misaka{
        int a,b;
        int val;
    }edge[N];
    
    int n,m,q;
    int p[N];
    ll sz[N];
    
    int find(int x){
        if(p[x]!=x) p[x]=find(p[x]);
        return p[x];
    }
    
    signed main() {
        int _;
        scanf("%lld",&_);
        while(_--){
            scanf("%lld %lld %lld",&n,&m,&q);
            for(int i=1;i<=m;++i){
                int u,v,val;
                scanf("%lld %lld %lld",&u,&v,&val);
                edge[i]={u,v,val};
            }
            vector<PLL> query(q+1);
            vector<int> res(q+1);
            for(int i=1;i<=q;++i){
                scanf("%lld",&res[i]);
                query[i].fi=res[i];
                query[i].se=i;
            }
            sort(query.begin()+1,query.end());
            sort(res.begin()+1,res.end());
            sort(edge+1,edge+1+m,[&](misaka x,misaka y){
                return x.val>y.val;
            });
            for(int i=1;i<=n;++i) p[i]=i,sz[i]=1;
            vector<ll> ans(q+1);
            ll sum=0;
            for(int i=1;i<=m;++i){
                int a=edge[i].a;
                int b=edge[i].b;
                int val=edge[i].val;
                int fa=find(a);
                int fb=find(b);
                if(fa!=fb){
                    p[fa]=fb;
                    int pos=upper_bound(res.begin()+1,res.end(),val)-res.begin()-1;
                    sum+=sz[fa]*sz[fb];
                    ans[query[pos].se]=sum;
                    sz[fb]+=sz[fa];
                }
            }
            for(int i=q-1;i>=1;--i){
                ans[query[i].se]=max(ans[query[i].se],ans[query[i+1].se]);
            }
            for(int i=1;i<=q;++i){
                printf("%lld\n",ans[i]);
            }
        }
        return 0;
    }
    
    
posted @ 2021-09-04 19:38  _Kolibri  阅读(132)  评论(0)    收藏  举报