牛客 7079 C - 牛牛的无向图 (离线 + 并查集)

链接: C - 牛牛的无向图
在这里插入图片描述

题意:
一个 n 个点 m 条边的无向图 , 对于每次询问,求出有多少个点对之间的 dis 小于 L , dis定义为 u 能到达 v 的 所有路径中权值最小的路径的权值。

思路:
要是最小路径小于 L ,我们可以对路径大小进行排序,在路径长度小于 L之前的任意两点都是符合的,所以可以用并查集维护连通块的大小 size ,它的贡献就是 C(size , 2) , 同时我们也对 L 进行排序 , 这样就可以依次求出每一个询问。

代码:


#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=2e6+7;
unsigned int SA, SB, SC; int n, m, q, LIM;
int L[maxn],fa[maxn];
ll cnt[maxn], ans[maxn];
struct node{
    int u,v,w;
}e[maxn];
bool cmp(node a,node b){
    return a.w < b.w;
}
int find(int x){
    if(fa[x] != x) fa[x] = find(fa[x]);
    return fa[x];
}
void conbine(int u,int v){
    int temp1 = find(u);
    int temp2 = find(v);
    if(temp1 != temp2){
        cnt[temp1] += cnt[temp2];
    }
    fa[temp2] = temp1;
}
unsigned int rng61(){
    SA ^= SA << 16;
    SA ^= SA >> 5;
    SA ^= SA << 1;
    unsigned int t = SA;
    SA = SB;
    SB = SC;
    SC ^= t ^ SA;
    return SC;
}
void gen(){
    scanf("%d%d%d%u%u%u%d", &n, &m, &q, &SA, &SB, &SC, &LIM);
    for(int i = 1; i <= m; i++){
        e[i].u = rng61() % n + 1;
        e[i].v = rng61() % n + 1;
        e[i].w = rng61() % LIM;
    }
    for(int i = 1; i <= q; i++){
        L[i] = rng61() % LIM;
    }
}
int main(){
   gen();
   sort(e + 1, e + m + 1,cmp);
   sort(L + 1,L + q + 1);
   for(int i = 0 ; i <= n; i ++){
       fa[i] = i;
       cnt[i] = 1;
   }
   ll k = 1,temp = 0;
   for(int i = 1; i <= m; i ++){
       int u = e[i].u,v = e[i].v,w = e[i].w;
       while(w > L[k]){
           ans[k++] = temp;
           if(k > q) break;
       }
       if(k > q) break;
       int x = find(u),y = find(v);
       if(x == y) continue;
       temp = temp - cnt[x] * (cnt[x] - 1) / 2 - cnt[y] * (cnt[y] - 1) / 2 + (cnt[x] + cnt[y]) * (cnt[x] + cnt[y] - 1) / 2;
       conbine(x,y);
   }
   for(int i = k; i <= q; i ++){
       ans[i] = temp;
   }
   ll anss = 0;
   for(int i = 1; i <= q; i ++) anss = anss ^ ans[i];
   printf ("%lld\n",anss);













}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值